2016-11-19 99 views
0

我從書上讀到的事件驅動編程:執行上下文驅動的編程

Practical UML Statecharts in C/C++, 2nd Edition: Event-Driven Programming for Embedded Systems

在頁面沒有。二十八介紹,作者說:

...事件驅動的應用程序必須處理 每次活動後返回控制,所以執行上下文不能在 基於堆棧的變量和程序計數器,因爲它被保留在順序 程序中。相反,事件驅動的應用程序變成了一個狀態機器,或者實際上是一組協作狀態機,它們將變量中的一個事件保持在下一個事件中的下一個狀態機器。

我無法理解爲什麼在處理事件後返回控件後,無法在基於堆棧的變量和程序計數器中保留執行上下文?

回答

1

讓我們從傳統的順序編程範例的工作開始。假設你想讓嵌入式主板上的LED閃爍。一個常見的解決方案是將寫一個程序是這樣的(例如,參見Arduino Blink tutorial):

while (1) { /* RTOS task or a "superloop" */ 
    turn_LED_on(); /* turn the LED on (computation) */ 
    delay(500);  /* wait for 500 ms (polling or blocking) */ 
    turn_LED_off(); /* turn the LED off (computation) */ 
    delay(1000); /* wait for 1000 ms (polling or blocking) */ 
} 

這裏的關鍵點是delay()函數,它等待在線直到延遲爲止。這個等待被稱爲「阻塞」,因爲呼叫程序被阻止,直到delay()返回。

請注意的Blinky程序調用兩個delay()不同的上下文:turn_LED_on()之後的第一時間和turn_LED_off()後的第二次。每次,delay()都返回到代碼中的不同位置。這意味着,當程序被阻止時,代碼中的地點信息(呼叫的上下文)會自動保存。

Blinky程序非常簡單,但原則上阻塞函數,如delay(),可以從其他函數調用,每個函數都有 複雜的if-else-while代碼。但是,delay()將能夠返回到調用的確切點,因爲C編程語言保留了調用的上下文(在調用堆棧和程序計數器中)。

但阻止使整個程序對任何其他事件沒有響應,因此人們想出了event-driven programming

事件驅動程序圍繞event-loop構建。一個例子事件驅動的代碼看起來是這樣的:

while (1) { /* event-loop */ 
    Event *e = queue_get(); /* block when event queue is empty */ 
    dispatch(e); /* handle the event, cannot block! */ 
} 

主要的一點是,dispatch()「事件處理程序」功能不能呼叫阻塞函數像delay()。相反,dispatch()只能執行一些即時操作,並且必須快速返回到事件循環。這樣,事件循環始終保持響應

但是,通過返回dispatch()函數從調用堆棧中刪除自己的堆棧幀。所以與調用dispatch()相關聯的調用堆棧和程序計數器總是相同的,並且無法「記住」執行上下文。

相反,要使LED閃爍,dispatch()功能必須依賴一些記憶LED狀態(開/關)的變量(state)。你怎麼能寫這樣dispatch()功能的示例如下:

static enum {OFF, ON } state = OFF; /* start in the OFF state */ 
timer_arm(1000); /* arm a timer to generate TIMEOUT event in 1000 ms */ 

void dispatch(Event *e) { 
    switch (state) { 
     case OFF: 
      if (e->sig == TIMEOUT) { 
       turn_LED_on(); 
       timer_arm(500); 
       state = ON; /* transition to "ON" state */ 
      } 
     break; 
     case ON: 
      if (e->sig == TIMEOUT) { 
       turn_LED_off(); 
       timer_arm(1000); 
       state = OFF; /* transition to "OFF" state */ 
      } 
     break; 
    } 
} 

我希望你能看到dispatch()實現與ON和OFF由一個事件驅動TIMEOUT狀態的state machine

相關問題