Protothread存在於contiki、uip中,作者是Dunkels, Adam。
官網介紹prothread
Protothreads is a mixture of the event-driven and the multi-threaded programming mechanisms. With protothreads, event-handlers can be made to block, waiting for events to occur.
Find the code in contiki/core/sys/pt.h
.
用戶創建線程使用系統提供的API,
static int user_pthread( struct pt *pt)
{
PT_INIT(pt);
PT_BEGIN(pt);
PT_WAIT_UNTIL(pt, your_event == event_buff);
/*User's code put here */
user_code;
}
PT的一個核心結構體
struct pt {
lc_t lc;
};
lc是local的意思,表示線程的一個變量,作爲狀態的一個判斷值。
PT_INIT()、PT_BEGIN()、PT_WAIT_UNTIL()是PT_FSM提供給用戶的API,本質上是宏定義。先看一下PT_INIT()原型,#define PT_INIT(pt) LC_INIT((pt)->lc),
#define LC_INIT(s) s = 0;
s是state狀態的意思,一開始讓 s = 0, 原因是爲了運行下一句代碼PT_BEGIN(), PT_BEGIN()定義如下
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
#define LC_RESUME(s) switch(s) { case 0:
PT_WAIT_UNTIL()的作用就是判斷事件是否符合用戶的要求,如果符合則觸發用戶代碼,否則退出線程。該宏定義如下
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while(0)
#define LC_SET(s) s = __LINE__; case __LINE__: 這個宏定義就類似與傳統操作系統的任務切換保護上下文的關鍵地方,設置S = __LINE__, 然後 case __LINE__, 使CPU可以繼續向下繼續運行,判斷條件是否符合,return 就是切換線程的關鍵點,當下次執行到該線程時候,可以從斷點繼續運行,所以LINE就是保護上下文的變量,而這個變量是編譯器的一個關鍵字,用以指示本行語句在源文件中的位置信息,佔用空間兩個字節。這裏也體現了實時性,切換線程時候,相對於傳統操作系統,並不需要人爲去保存線程上下文。PT_WAIT_UNTIL可以靈活放置在用戶代碼中,以便從斷點繼續運行。這裏是最關鍵的設計。
所以三個宏展開,整體看起來就是
S = 0
Switch (s){
Case 0:
/*Three line is the key to switch thread, real time*/
S = __LINE__;
Case __LINE__:
if( !condition )
return 0;
}
PT是一種抽象的編程軟件框架,它提供了條件阻塞狀態語句,PT_WAIT_UNTIL(), 旨在針對內存受限制的一種簡化事件編程驅動模型的嵌入式軟件系統。該系統提供條件語句阻塞線程,直到線程滿足條件纔可以繼續執行。如果第一次運行到PT_WAIT_UNTIL(), 條件滿足,那麼線程繼續執行,不會受到其他干擾。PT_WAIT_UNTIL()是每一次執行線程必須經過的代碼,條件可以是任意類型。如果條件不滿足,保存當前代碼行號,下次切換到此任務時,利用該swich的控制變量,在這斷點執行。
總結:PT 佔用內存小,十幾個字節就可以運行,可以多任務運行,每個任務保存上下文只佔用兩個字節。
缺點:線程的局部變量在切換任務時候會丟失數據,使用不當會造成災難性的BUG,可以準確的的說,PT切換任務時候,只保存斷點信息,並未真正保存任務寄存器的信息。