年輕人會用C 實現一種協程嗎?

2021-10-11 05:29:49 字數 2987 閱讀 9565

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

我有見過幾種協程的實現,因為沒有 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 檔案中。

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 listif(

!setjmp

(current-

>buf))if

(stoppedroutines.

size()

)}

使用者的**很簡單,就像使用乙個執行緒庫一樣,乙個協程主動呼叫 switch() 函式主動讓出 cpu 時間給另乙個協程。

#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...