因為協程的好處,是以協程庫現在有好多 libtask,boost::coroutine,libco......
libtask很不錯,以後或許會用。
boost我個人基本很少用。
騰訊的 libco自己用彙編實作了swapcontext函數,不明覺厲(libtask也有ASM)。而且把epoll整合在了裡面。
微信背景就用到了它.在chinaunix.net上的一個 文章中就說到了這個。不過暫不适合我。
還好雲風實作過一個coroutine庫,用的context系列函數,很精巧的封裝,代碼量很小, 也沒附加啥其它特性。用來加深了解再好不過。
在 http://blog.codingnow.com/2012/07/c_coroutine.html 上有其相關說明。
不過代碼沒注釋啥的,為了怕忘記一些體會,我按個人了解加了代碼注釋, 在上Github上儲存了一份.
https://github.com/xcltapestry/coroutine (了解不深,如有錯誤歡迎指正).
至于下面是針對這個庫的一些點,記錄一下.
1. 結構體schedule與coroutine的參數意義
struct schedule {
char stack[STACK_SIZE]; //運作時,co上下文用的就是這塊記憶體. 厲害
ucontext_t main; //上下文資訊
int nco; //實際的co指針個數
int cap; //co指針數組大小
int running; // 目前處理的co數組id 或 -1
struct coroutine **co; //co指針數組
};
// ptrdiff_t 用于表示指針間的"距離",對于指針加減的結果可用這個類型來表示.
struct coroutine {
coroutine_func func; //使用者自定義的函數
void *ud; //使用者自定義的函數,所傳進來的參數,在此為main中的statuc arg
ucontext_t ctx; //上下文資訊就不用多說了
struct schedule * sch; //指向co所歸屬的Sch.
ptrdiff_t cap; //容量
ptrdiff_t size; //占用的棧大小
int status; // COROUTINE_SUSPEND/COROUTINE_READY
char *stack; //在yield/resume時發揮儲存和恢複作用
};
2. 64位指針的傳遞
//注意這裡從相容性角度把S這個指針拆了下,原因是大部份編譯器在32/64位下,
//sizeof(指針)傳回的長度是不一樣的, 32位下是4個位元組,64位下是8個位元組
//是以在makecontext()的這個可變參數中,将其拆分成了兩個32位的指針來傳.
//附:在執行位址運算時,多用 uintptr_t 和 uint32_t,更清晰,安全性與相容性更好
uintptr_t ptr = (uintptr_t)S;
makecontext(&C->ctx, (void (*)(void)) mainfunc, 2, (uint32_t)ptr, (uint32_t)(ptr>>32));
3. 上下文記憶體和棧記憶體的一些處理
棧拷貝,按需配置設定
_save_stack(struct coroutine *C, char *top)
top - &dummy 确實用的好.
top是棧頂位址, 通過top - &dummy得到棧的實際所需大小配置設定組C->stack,
然後在resume時可以從這弄回去.
引用:
"因為,在我的應用場合,coroutine 切換的那一刻,使用的堆棧并不多(它可能調用一些需要大量堆棧的庫函數,但那些庫函數中并不會發生切換),是以,在切換的時刻做棧拷貝是可以接受的。coroutine 切換并不算頻繁,這個切換成本是可控的。"
char stack[STACK_SIZE]; //運作時,co上下文用的就是這塊記憶體
引用:
"其次,我不希望使用 coroutine 的人太考慮 stack 大小的問題。就是說,使用者在 coroutine 内可以使用的 C stack 大小和主線程一樣多。"
4. 在開發32/64位程式時,以後應當多使用ptrdiff_t,uintptr_t 和 uint32_t這類為了跨平台而定義的東東.
這類東西定義在 stdint.h 中. 在Windows下我用vs2005嘗試時,悲劇的發現2005不支援這個,查到的解決方法是通路
http://www.azillionmonkeys.com/qed/pstdint.h
然後将裡面的内容複制到自己新增的stdint.h中即可用了,以後如vs2010支援了再去掉就行了.
協程庫這東西不簡單。
MAIL: [email protected]
BLOG: http://blog.csdn.net/xcl168