嵌入式开发系列教程(六) 并发模型之回调

在上一单元中,我们制作了一个简单的事件循环框架。

int main()
{
    int event;
    eventHandler func;
    while(1){
        event = Event();     //事件检测
        if(event != -1){
            func = findEventHandler(event);  //事件匹配,分发
            func();                           //事件处理
        }
    }
}

我们发现,如果某一个事件处理函数出现了阻塞,将会导致整个事件循环阻塞,进而其他事件也无法处理。其实,这是典型的并发问题,解决这种问题,有三种编程模型

  • 回调模
  • 协程模型
  • 多线程、多进程模型

回调模型

回调实现LED闪烁功能,点亮3s,熄灭3s

void LedFlash()   //led闪烁,点亮3s,熄灭3s
{
    if(LED == ON)
        LED = OFF;
    else
        LED = ON;
    setTimerEvent(3000,LedFlash); //定时器,每隔3s调用一次LedFlash函数
}

如果是点亮3s,熄灭5s呢?

void LedOn()
{
    LED = ON;
}

void LedOff()
{
    LED = OFF;
}

void LedFlash()   //led闪烁,点亮3s,熄灭5s
{
    if(LED == ON){
        LedOff();     //熄灭LED灯
        setTiemrEvent(5000,LedOn);  //5s后,再点亮LED灯
    }
    else{
        LedOn();  //点亮LED灯
        setTiemrEvent(3000,LedOff);  //3s后,再熄灭LED灯
    }
}

我们看到,LedFlash的逻辑已经比较复杂,但我们还能直观的观察到代码逻辑。可如果是,先点亮3s,再熄灭5s,然后点亮5s,再熄灭3s呢?

static int LED;
static int FLASH;   //第几次闪烁(第一次或第二次)
void LedOn()
{
    LED = ON;
}

void LedOff()
{
    LED = OFF;
}

void LedFlash()   //led闪烁,点亮3s,熄灭5s
{
    if(FLASH == first){  // 第一次闪烁
        if(LED == ON){
            LedOff();     //熄灭LED灯
            setTiemrEvent(5000,LedOn);  //5s后,再点亮LED灯
        }else{
            LedOn();  //点亮LED灯
            FLASH = sencond; //你能在5s之内想明白这个变量应该怎么赋值么??
            setTiemrEvent(3000,LedOff);  //3s后,再熄灭LED灯
        }
    }
    if(FLASH == second){  // 第二次闪烁
        if(LED == ON){
            LedOff();     //熄灭LED灯
            setTiemrEvent(3000,LedOn);  //3s后,再点亮LED灯
        }else{
            LedOn();  //点亮LED灯
            Flash = first   //你能在1min之内想明白这个变量应该怎么赋值么??
            setTiemrEvent(5000,LedOff);  //5s后,再熄灭LED灯
        }
    }

}

首先,代码量陡增,维护就会比较麻烦,代码逻辑也非常不直观

其实,在上面的编程过程中,我们一直用到了状态机的解决方案,只不过没有明确的表达出来,现在我们根据状态机的思路,再重新看一便上面的代码逻辑

  • 先点亮3s, 第一次闪烁FLASH=first,当前LED灯是熄灭状态LED=OFF STATE = 0x10
  • 再熄灭5s, 第一次闪烁FLASH=first,当前LED灯是点亮状态LED=ON STATE = 0x11
  • 然后点亮5s, 第二次闪烁FLASH=second,当前LED灯是熄灭状态LED=OFF STATE = 0x20
  • 再熄灭3s 第二次闪烁FLASH=sencond,当前LED灯是点亮状态LED=ON STATE = 0x21
static int STATE = 0x10;

void LedFlash()
{
    switch(STATE){
        case 0x10:
            LED = ON;  //点亮LED灯
            STATE = 0x11;  //切换状态
            setTimerEvent(3000,LedFlash);
            break;
        case 0x11:
            LED = OFF;  
            STATE = 0x20;  //切换状态
            setTimerEvent(5000,LedFlash);
            break;
        case 0x20:
            LED = ON;  
            STATE = 0x21;  //切换状态
            setTimerEvent(5000,LedFlash);
            break;
        case 0x21:
            LED = OFF; 
            STATE = 0x10;  //切换状态
            setTimerEvent(3000,LedFlash);
            break;
    }
}

虽然我们改善了代码逻辑,但是本质上来讲,回调模型把正常逻辑的执行流程做了切割,逻辑不自然,但其模型设计简单,效率高

其实对于上面的需求,我们更希望看到这样的代码

void LedFlash()
{
    LedOn();
    delay(3);    //点亮3s
    LedOff();
    delay(5);     //熄灭5s
    LedOn();
    delay(5);     //点亮5s
    LedOff();
    delay(3);     //熄灭3s
}

看到这种代码,大家可能会第一时间想到线程、进程模型。这里提醒一下,下一单元我们从协程切入。

这是一个免费,开源的教程,如果你喜欢可以转发,也可以打赏奖励。 欢迎关注微信公众号小站练兵

你可能感兴趣的:(嵌入式开发系列教程(六) 并发模型之回调)