基於Duff's Device的C簡易無棧協程實現
阿新 • • 發佈:2020-10-22
參考 Simon Tatham 的文章https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
譯文為https://mthli.xyz/coroutines-in-c/
協程是一組序列化的子過程,與執行緒不同,協程的排程是由使用者而非作業系統執行的,協程可以在任意時刻讓出CPU(稱為yield操作),下次呼叫時從上次yield的地方繼續執行
Simon Tatham利用Duff's Device實現了一種簡易的無棧協程,示例程式碼如下:
int function(void) { static int i, state = 0; switch (state) { case 0: for (i = 0; i < 10; i++) { state = 1; return i; case 1:; } } }
該函式的作用是第i次呼叫時返回i,最多10次(相同的函式功能可以通過一個statci變數實現,但本文是為了討論協程),其核心部分為switch語句以及return前後兩句,通過設定不同的state來保證下一次呼叫時從上次退出的地方繼續執行(如果不明白switch為何能和for套在一起寫可以自行搜尋Duff's Device)
可以看出,每次呼叫return時設定的state必須不同,可以利用__LINE__巨集來設定state,這樣只要不在一行呼叫兩次return即可
以下是將其用巨集封裝的程式碼
#include <stdio.h> #define crBegin static int state = 0; switch (state) { case 0: #define crReturn(x) do { state = __LINE__; return x; case __LINE__:; } while (0) #define crFinish } void f1() { crBegin; puts("1"); puts("2"); crReturn(); puts("3"); crFinish; } void f2() { crBegin; puts("x"); crReturn(); puts("y"); puts("z"); crFinish; } int main (void) { f1(); f2(); f1(); f2(); return 0; }
do while(0)是為了讓crReturn與if else巢狀時不用考慮大括號問題
這份程式碼執行後會依次輸出1,2,x,3,y,z
至此,一份用C實現的簡易無棧協程就完成了,需要注意的是,因為switch內部不能任意定義變數,請在crBegin之前定義所需變數
PS:這份程式碼僅供學習參考,如果你在實際生產程式碼中用了可能會被上司打死