前言:在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。我有見過幾種協程的實現,因為沒有 c/c++ 的原生支援,所以多數的庫使用了彙編**,還有些庫利用了 c 語言的 setjmp 和 longjmp 但是要求函式裡面使用 static local 的變數來儲存協程內部的資料。我討厭寫彙編和使用 static local 變數,所以想出了一種稍微優雅一點又有點奇技淫巧的實現方法。 這篇文章將向你展示這種方法基本原理和實現。
用 c/c++ 實現的最大困難就是建立,儲存和恢復程式的上下文。因為這涉及到了程式棧的管理,以及 cpu 暫存器的訪問,但是這兩項內容在 c/c++ 標準裡面都沒有嚴格的定義,所以我們是不可能有乙個完全跨平台的 c/c++ 實現的。但是利用作業系統提供的 api,我們仍然可以避免使用彙編**,接下來會向你展示使用 posix 的 pthread 實現的一種簡單的協程框架。什麼!??pthread?那你的程式豈不是多執行緒了?那還叫協程嗎!沒錯,確實是多執行緒的,不過僅僅是在協程被建立之前的短暫瞬間。
下面是 routineinfo 的定義。為了簡單起見,所有錯誤處理**都被省略了,原版本的**在 coroutine.cpp 檔案中,省略版的**在 coroutine_demonstration.cpp 檔案中。
然後,我們需要一下全域性的列表來儲存這些 routineinfo 物件。typedef
void*(
*routinehandler)
(void*)
;struct routineinfo
~routineinfo()
};
接下來是協程的建立,注意當協程的時候,程式棧有可能已經被損壞了,所以需要乙個stackback作為程式棧的備份,用來做後面的恢復。std::list
>
initroutines()
std::list
> routines =
initroutines()
;
然後是 coroutinnestart 函式。當執行緒進入這個函式的時候,使用setjmp儲存上下文,然後備份它自己的程式棧,然後直接退出執行緒。void
*stackbackup =
null
;void
*coroutinestart
(void
*proutineinfo)
;int
createcoroutine
(routinehandler handler,
void
* param )
乙個協程主動呼叫 switch() 函式,才切換到另乙個協程。void
switch()
;void
*coroutinestart
(void
*proutineinfo)
info.ret = info.
handler
(info.param);
info.stopped =
true
;switch()
;// never return
return
(void*)
0;// suppress compiler warning
}
使用者的**很簡單,就像使用乙個執行緒庫一樣,乙個協程主動呼叫 switch() 函式主動讓出 cpu 時間給另乙個協程。std::list
> stoppedroutines = std::list
>()
;void
switch()
routines.
push_back
(current)
;// adjust the routines to the end of listif(
!setjmp
(current-
>buf))if
(stoppedroutines.
size()
)}
#include
using
namespace std;
#include
void
*foo
(void*)
}int
main()
}
[roxma@vm_6_207_centos coroutine]$ g++ coroutime_demonstration.cpp -lpthread -o a.out
[roxma@vm_6_207_centos coroutine]$ ls
a.out coroutime.cpp coroutime_demonstration.cpp readme.md
[roxma@vm_6_207_centos coroutine]$ .
/a.out
main:
0foo:
0main:
1foo:
1main:
2main:
3main:
4main:
5
一種協程的 C C 實現
在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。我有見過幾種協程的實現,因為沒有 c ...
協程卡死的一種情況
在使用 libco 的時候,不正確的用法會導致協程排程不正常。分享最近遇到的問題。在協程環境下,呼叫了使用標準鎖的函式。rpc 框架是乙個多執行緒多協程的模型,在乙個執行緒下會開啟多個協程,請求來了之後會由協程呼叫業務處理函式。最近加了乙個併發優化後,發現會出現請求卡住不呼應的問題。最終定位到就是 ...
年輕人第一道C語言面試題
題目 請問以下例1和例2的str有什麼區別?例1 include int main int argc,char ar printf s n str 例2 include int main int argc,char ar 解析 術語 例1字串陣列,例2字串指標 關鍵點 例1 例2的str和hello...