在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。
我有見過幾種協程的實現,因為沒有 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()
};
接下來是協程的建立,注意當協程的時候,程式棧有可能已經被損壞了,所以需要乙個std::list
initroutines()
std::list
routines = initroutines();
stackback
作為程式棧的備份,用來做後面的恢復。
然後是 coroutinnestart 函式。當執行緒進入這個函式的時候,使用void *stackbackup = null;
void *coroutinestart
(void *proutineinfo)
;int
createcoroutine
(routinehandler handler,void* param )
setjmp
儲存上下文,然後備份它自己的程式棧,然後直接退出執行緒。
乙個協程主動呼叫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()
函式,才切換到另乙個協程。
使用者的**很簡單,就像使用乙個執行緒庫一樣,乙個協程主動呼叫std::list
stoppedroutines = std::list
();void
switch
()
routines.push_back(current); // adjust the routines to the end of list
if( !setjmp(current->buf) )
if(stoppedroutines.size())
}
switch()
函式主動讓出 cpu 時間給另乙個協程。
記得在鏈結的時候加上#include
using
namespace
std;
#include
void* foo
(void*)
}int
main
()}
-lpthread
鏈結選項。程式的執行結果如下所示:
[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
**啊自:
協程卡死的一種情況
在使用 libco 的時候,不正確的用法會導致協程排程不正常。分享最近遇到的問題。在協程環境下,呼叫了使用標準鎖的函式。rpc 框架是乙個多執行緒多協程的模型,在乙個執行緒下會開啟多個協程,請求來了之後會由協程呼叫業務處理函式。最近加了乙個併發優化後,發現會出現請求卡住不呼應的問題。最終定位到就是 ...
C C 協程的實現方式總結
1 利用 c 語言的 setjmp 和 longjmp,函式中使用 static local 的變數來儲存協程內部的資料。函式原型 int setjmp jmp buf envbuf void longjmp jmp buf envbuf,int val 先呼叫setjmp,用變數envbuf記錄當...
年輕人會用C 實現一種協程嗎?
前言 在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。我有見過幾種協程的實現,因為沒有...