隨着嵌入式系統的廣泛應用,對系統的可靠性和實時性等需求也越來越高。而協程技術能夠很好地解決這些問題。Protothread就是一種輕量級協程技術,下面我們將從多個方面對其進行詳細的闡述。
一、Protothread概述
Protothread是一種基於C語言的、輕量級的、面向事件驅動的協程技術,它的核心思想是將協程處理儘可能小的處理單元,並使用狀態變量指示協程的運行進度,從而向外部事件響應和傳達執行進度。
Protothread中的協程都被視為很簡單、幾乎等價於無狀態機的程序代碼。這些協程的特徵在於它們能夠暫停它們的狀態機,並在下一次調用時從上次離開的地方繼續執行。協程的執行順序決定了程序代碼的執行順序,這種執行順序已經預先定義的,從而協程就成為了輕量級進程。
Protothread可以使用非搶佔式多任務處理技術來管理協程,這種技術可以將系統中每個任務的執行時間分割成明確的時間片,然後輪流執行多任務。在這個過程中,Protothread可以及時捕獲外部事件並響應,從而使得整個系統保持高效和穩定。
Protothread和狀態機最大的不同點在於,狀態機是由開發人員定義並手動控制執行路徑,而Protothread則嘗試通過代碼的命名和邏輯表達使得代碼自動化生成。從而使得工程師不用手動維護狀態機更新與之間的關係問題。
二、Protothread的實現
Protothread的實現是通過多個狀態和對應的協程來實現的,每個狀態對應一個協程,同時協程中還有一個表示執行狀態的整型變量,用於在不同狀態之間進行狀態轉換和執行流程控制。
我們可以將這個整型變量稱作協程的「狀態」變量,當協程執行完一種狀態之後,就將其狀態變量設置為下一種狀態,從而協程就繼續沿着設計的程序執行路徑進行處理。
typedef struct {
unsigned short pt_running;
unsigned short pt_lastline;
unsigned short pt_linedefined;
} pt_thread;
#define PT_THREAD_NAME(name_args) char name_args; \
int name_args##_thread(pt_thread *pt, int state)
#define PT_BEGIN(pt) int PT_CONTINUATION_STATE = 0; switch(PT_CONTINUATION_STATE) { case 0:
#define PT_WAIT_UNTIL(pt, condition) PT_CONTINUATION_STATE= __LINE__; case __LINE__: \
if(!(condition)) return 0
#define PT_END(pt) }
#define PT_YIELD(pt) do {
PT_CONTINUATION_STATE = __LINE__; \
return __LINE__; case __LINE__:;} while(0)
上面這段代碼展示了典型的PT協程重寫,它使用了會產生對嵌套函數調用的switch/case語句,這些switch和case語句用於在協程中實現對PT_STATE的調度處理。
要使用PT協程,只需要包括「PT_THREAD_NAME(name_args)」在函數前面,在你的協程函數中就可以使用在裸庫中使用的PT_WAIT_UNTIL, PT_WAIT_WHILE, PT_SPAWN或PT_YIELD等等協程語句。此外,該PT_THREAD_NAME宏展開為一個帶有一個單獨pt_thread參數的函數。pt_thread數據結構提供了一個狀態運行參數,一個最後一行運行標記和一個行定義標記。
三、Protothread的優點和適用場景
Protothread作為一種輕量級協程技術,在許多嵌入式系統中都得到了廣泛的應用。
首先,Protothread運行效率高,因為它使用了非搶佔式多任務處理技術,能夠最大限度地提高系統效率,而且代碼清晰簡潔、易於維護。同時,使用Protothread的嵌入式系統在性能和實時性方面都能夠得到保證。
其次,Protothread的編碼方式比傳統的狀態機更易於實現。其中的協程特徵允許在協程間共享變量,並同時使用同一複雜狀態機。這種方法更容易管理並測量,因為它減少了設計中的狀態轉換數量。
最後,當我們面對的系統的複雜性增加時,Protothread能夠輕鬆地擴展。開發人員只需將更多的協程加入到系統中,而不必更改已有的協程。
四、Protothread的示例
static struct pt pt1, pt2;
static PT_THREAD(protothread1(struct pt *pt)) {
PT_BEGIN(pt);
for(;;) {
PT_WAIT_UNTIL(pt, input_a);
PT_WAIT_UNTIL(pt, input_b);
output_c = input_a + input_b;
LCD_Display(output_c);
}
PT_END(pt);
}
#define STATE_IDLE 0
#define STATE_INIT 1
#define STATE_SEND 2
#define STATE_DONE 3
u16 seq_no;
u8 buffer[200];
u8 sys_buf[32];
u32 sys_buf_len;
static PT_THREAD(protothread2(struct pt *pt)) {
PT_BEGIN(pt);
while(1) {
PT_WAIT_UNTIL(pt, PT_SEM_WAIT(pt, serial_rx) != 0);
if((serial_rx_buffer.head != serial_rx_buffer.tail) &&
((serial_rx_buffer.head > serial_rx_buffer.tail) ||
((serial_rx_buffer.head == serial_rx_buffer.tail) &&
(serial_rx_buffer.data_cnt != 0)))) {
process_serial_rx_data();
}
}
PT_END(pt);
}
上面是一些常見的Protothread代碼實例,其中protothread1處理輸入A和輸入B,並將其相加輸出到LCD顯示屏上。另一個示例是protothread2,它使用PT協程將串行數據接收並交付到接受方。
這些示例展示了Protothread用於嵌入式系統的輕量級協程技術。由於Protothread使用非搶佔式多任務處理技術,因此可以有效地提高系統效率,同時代碼也更加簡潔易懂。
五、小結
Protothread是一種輕量級協程技術,它的核心思想是將協程的處理單元儘可能小,並使用狀態變量指示協程的運行進度。它在許多嵌入式系統中得到了廣泛應用,具有運行效率高、編碼簡單等優勢。掌握Protothread技術,對於嵌入式系統開發工程師來說是一個非常有意義的技能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/291717.html