天天看點

協程庫的一些筆記

因為協程的好處,是以協程庫現在有好多 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