一種協程的 C C 實現

2021-07-11 02:25:20 字數 2680 閱讀 6073

在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。

我有見過幾種協程的實現,因為沒有 c/c++ 的原生支援,所以多數的庫使用了彙編**,還有些庫利用了 c 語言的setjmplongjmp但是要求函式裡面使用 static local 的變數來儲存協程內部的資料。我討厭寫彙編和使用 static local 變數,所以想出了一種稍微優雅一點又有點奇技淫巧的實現方法。 這篇文章將向你展示這種方法基本原理和實現。

用 c/c++ 實現的最大困難就是建立,儲存和恢復程式的上下文。因為這涉及到了程式棧的管理,以及 cpu 暫存器的訪問,但是這兩項內容在 c/c++ 標準裡面都沒有嚴格的定義,所以我們是不可能有乙個完全跨平台的 c/c++ 實現的。但是利用作業系統提供的 api,我們仍然可以避免使用彙編**,接下來會向你展示使用 posix 的 pthread 實現的一種簡單的協程框架。什麼!??pthread?那你的程式豈不是多執行緒了?那還叫協程嗎!沒錯,確實是多執行緒的,不過僅僅是在協程被建立之前的短暫瞬間。

下面是 routineinfo 的定義。為了簡單起見,所有錯誤處理**都被省略了,原版本的**在coroutine.cpp檔案中,省略版的**在coroutine_demonstration.cpp檔案中。

typedef

void * (*routinehandler)(void*);

struct routineinfo

~routineinfo()

};

然後,我們需要一下全域性的列表來儲存這些 routineinfo 物件。

std::list

initroutines()

std::list

routines = initroutines();

接下來是協程的建立,注意當協程的時候,程式棧有可能已經被損壞了,所以需要乙個stackback作為程式棧的備份,用來做後面的恢復。

void *stackbackup = null;

void *coroutinestart

(void *proutineinfo)

;int

createcoroutine

(routinehandler handler,void* param )

然後是 coroutinnestart 函式。當執行緒進入這個函式的時候,使用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 實現一種協程嗎?

前言 在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。我有見過幾種協程的實現,因為沒有...