欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言中實(shí)現(xiàn)協(xié)程案例

 更新時(shí)間:2021年07月02日 16:42:23   作者:adinosaur  
這篇文章主要介紹了C語(yǔ)言中實(shí)現(xiàn)協(xié)程案例,本文通過(guò)將協(xié)程與線程和異步回調(diào)進(jìn)行對(duì)比,以及具體實(shí)現(xiàn)案例,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

協(xié)程是一種用戶空間的非搶占式線程,主要用來(lái)解決等待大量的IO操作的問(wèn)題。

協(xié)程vs線程

對(duì)比使用多線程來(lái)解決IO阻塞任務(wù),使用協(xié)程的好處是不用加鎖,訪問(wèn)共享的數(shù)據(jù)不用進(jìn)行同步操作。這里需要說(shuō)明的一點(diǎn)是,使用協(xié)程之所以不需要加鎖不是因?yàn)樗械膮f(xié)程只在一個(gè)線程中運(yùn)行,而是因?yàn)閰f(xié)程的非搶占式的特點(diǎn)。也就是說(shuō),使用協(xié)程的話,在沒(méi)主動(dòng)交出CPU之前都是不會(huì)被突然切換到其它協(xié)程上的。而線程是搶占式的,使用多線程你是不能確定你的線程什么時(shí)候被操作系統(tǒng)調(diào)度,什么時(shí)候被切換,因此需要用鎖到實(shí)現(xiàn)一種“原子操作”的語(yǔ)義。

協(xié)程vs異步回調(diào)

其實(shí)更一般更常見(jiàn)的做法是,使用非阻塞的IO(比如是異步IO,又或者是在syscall上自己實(shí)現(xiàn)的一套異步IO,如asio)并且將處理操作寫(xiě)在回調(diào)函數(shù)中。這樣的做法一般沒(méi)什么問(wèn)題,但當(dāng)回調(diào)函數(shù)變多,一段連貫的業(yè)務(wù)代碼就會(huì)被拆分到多個(gè)回調(diào)函數(shù)之中,增加維護(hù)的成本。因此使用協(xié)程可以用同步的寫(xiě)法寫(xiě)出效果相當(dāng)于是異步的代碼。

利用static變量實(shí)現(xiàn)協(xié)程

要實(shí)現(xiàn)一個(gè)協(xié)程,主要的問(wèn)題是如何保存函數(shù)調(diào)用的上下文。之前在網(wǎng)上看到一篇博客coroutines in c,用一種非常簡(jiǎn)潔的方式實(shí)現(xiàn)了這個(gè)保存上下文的功能。實(shí)現(xiàn)代碼如下:

#define crBegin static int _cr_state = 0; switch(_cr_state) { case 0:
#define crReturn(x) do { _cr_state = __LINE__; return x; case __LINE__:; } while (0)
#define crFinish }

int func1() {
    crBegin
    while (1)
    {
        printf("hello world\n");
        crReturn(0);
    }
    crFinish
}

這個(gè)代碼利用了函數(shù)的static變量來(lái)保存函數(shù)調(diào)用狀態(tài)。注意,由于vs2013有一個(gè)調(diào)試特性,所以vs2013的__LINE__的實(shí)現(xiàn)不是常量因此會(huì)編譯不通過(guò),使用gcc就可以編譯。這段代碼簡(jiǎn)單是簡(jiǎn)單但是有問(wèn)題,比如說(shuō)如果兩個(gè)協(xié)程調(diào)用同一個(gè)函數(shù),就會(huì)出錯(cuò)。因此博客里面提及這段代碼主要是給出一個(gè)思路,如果實(shí)際使用的話這樣子肯定是不行的。

利用setjmp、longjmp實(shí)現(xiàn)協(xié)程

前面說(shuō)過(guò),實(shí)現(xiàn)協(xié)程最主要的是保存函數(shù)的調(diào)用的上下文,而這些上下文主要就兩個(gè)部分:1.各個(gè)寄存器的值,2.函數(shù)調(diào)用棧。C語(yǔ)言里可以通過(guò)setjmp來(lái)保存函數(shù)調(diào)用時(shí),各寄存器的值。保存之后,便可以通過(guò)longjmp重現(xiàn)回到當(dāng)初setjmp的地方(可以理解成跨函數(shù)的goto)。但是,需要注意的是,setjmp僅負(fù)責(zé)保存寄存器的值,不負(fù)責(zé)維護(hù)其函數(shù)調(diào)用棧(這個(gè)看看setjmp的jmp_buf的結(jié)構(gòu)就知道了),因此必須由使用者來(lái)手動(dòng)的維護(hù)這個(gè)函數(shù)調(diào)用棧。使用setjmp、longjmp的一個(gè)常見(jiàn)的錯(cuò)誤就是,嘗試去longjmp到一個(gè)已經(jīng)執(zhí)行完的函數(shù),這時(shí)候雖然寄存器的值是當(dāng)時(shí)保存的值,但是調(diào)用棧已經(jīng)不是原來(lái)的調(diào)用棧了。

而我的做法是,在創(chuàng)建一個(gè)協(xié)程的時(shí)候在堆上申請(qǐng)一塊空間(大小為2M)作為協(xié)程的調(diào)用棧,然后在setjmp的時(shí)候,手動(dòng)更改寄存器esp的值,使其指向這個(gè)我自己創(chuàng)建的調(diào)用棧。因此在以后運(yùn)行的時(shí)候,這個(gè)協(xié)程就會(huì)使用我提供的那塊內(nèi)存作為棧。

我的這個(gè)協(xié)程庫(kù)提供了三個(gè)接口:

  1. coro_new:創(chuàng)建一個(gè)協(xié)程
  2. coro_yield:將控制權(quán)返回給調(diào)度協(xié)程
  3. coro_main:運(yùn)行調(diào)度協(xié)程

協(xié)程的控制流程如下:

  1. 通過(guò)coro_main運(yùn)行調(diào)度協(xié)程,并找出下一個(gè)運(yùn)行的協(xié)程,運(yùn)行之。
  2. 運(yùn)行這個(gè)協(xié)程直到其調(diào)用coro_yield將控制權(quán)返還給調(diào)度協(xié)程。
  3. 重復(fù)以上兩個(gè)步驟,直到所有協(xié)程運(yùn)行完畢。

這個(gè)協(xié)程庫(kù)實(shí)現(xiàn)的非常簡(jiǎn)單,只有100來(lái)行的代碼,當(dāng)然實(shí)現(xiàn)它的目的是為了提供一個(gè)最簡(jiǎn)單的協(xié)程模型,而不是一個(gè)功能完整、魯棒性強(qiáng)的能投入實(shí)際業(yè)務(wù)運(yùn)行的協(xié)程。

因此問(wèn)題還是有很多的:

  1. 比如當(dāng)在協(xié)程里面調(diào)用棧超過(guò)2M時(shí),這個(gè)是需要處理的,現(xiàn)在的代碼是沒(méi)有做的,理應(yīng)中斷程序,避免寫(xiě)壞堆,產(chǎn)生隨機(jī)的不可重現(xiàn)的問(wèn)題。
  2. 顯然在實(shí)現(xiàn)時(shí)沒(méi)有考慮到多線程,如果在多線程環(huán)境里面運(yùn)行,需要代碼做同步處理。
  3. 現(xiàn)在的這個(gè)版本的協(xié)程有一個(gè)約定,在協(xié)程里調(diào)用的函數(shù)不能阻塞在syscall,這顯然也是不科學(xué)的。一個(gè)完整的協(xié)程庫(kù),應(yīng)該包含一些常用的syscall的非阻塞的實(shí)現(xiàn),畢竟只有一個(gè)線程不能真的阻塞在這個(gè)調(diào)用上。

總結(jié)

當(dāng)然實(shí)現(xiàn)協(xié)程還有比較一些更好的方法,比如如果能用glibc的ucontext庫(kù)就可以基于這個(gè)庫(kù)來(lái)實(shí)現(xiàn),而不用自己手動(dòng)管理函數(shù)調(diào)用的上下文了,如云風(fēng)實(shí)現(xiàn)的協(xié)程庫(kù)。

到此這篇關(guān)于C語(yǔ)言中實(shí)現(xiàn)協(xié)程案例的文章就介紹到這了,更多相關(guān)C語(yǔ)言實(shí)現(xiàn)協(xié)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 4組C語(yǔ)言中順序讀寫(xiě)文件的函數(shù)分享

    4組C語(yǔ)言中順序讀寫(xiě)文件的函數(shù)分享

    這篇文章主要為大家詳細(xì)介紹了4組C語(yǔ)言中實(shí)現(xiàn)順序讀寫(xiě)文件的函數(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • C++中new的越界訪問(wèn)問(wèn)題

    C++中new的越界訪問(wèn)問(wèn)題

    越界訪問(wèn)指訪問(wèn)了不是程序申請(qǐng)的內(nèi)存區(qū)域,比如申請(qǐng)了5個(gè)字節(jié)的char數(shù)組,結(jié)果讀寫(xiě)數(shù)據(jù)的第六個(gè)元素,或者訪問(wèn)了釋放后的內(nèi)存等等。
    2016-04-04
  • C語(yǔ)言之函數(shù)遞歸的實(shí)現(xiàn)

    C語(yǔ)言之函數(shù)遞歸的實(shí)現(xiàn)

    本文主要介紹了C語(yǔ)言之函數(shù)遞歸的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++中的字符串(1)

    C++中的字符串(1)

    這篇文章主要簡(jiǎn)單介紹C++中的字符串,字符串就是連續(xù)的一連串字符,在C++當(dāng)中, 處理字符串的方式有兩種類型。一種來(lái)自于C語(yǔ)言,也被稱為C風(fēng)格字符串。另外一種是基于string類庫(kù),下面來(lái)看文章學(xué)校內(nèi)容
    2021-11-11
  • OpenCV實(shí)現(xiàn)亂序碎片復(fù)原

    OpenCV實(shí)現(xiàn)亂序碎片復(fù)原

    這篇文章主要介紹了通過(guò)OpenCV 直方圖相似度對(duì)比,實(shí)現(xiàn)將4張打亂順序的碎片拼接復(fù)原并展示原圖。文中的示例代碼講解詳細(xì),需要的朋友可以學(xué)習(xí)一下
    2021-12-12
  • Eclipse中C++連接mysql數(shù)據(jù)庫(kù)

    Eclipse中C++連接mysql數(shù)據(jù)庫(kù)

    這篇文章主要為大家詳細(xì)介紹了Eclipse中C++連接mysql數(shù)據(jù)庫(kù) ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • 數(shù)據(jù)結(jié)構(gòu)之伸展樹(shù)詳解

    數(shù)據(jù)結(jié)構(gòu)之伸展樹(shù)詳解

    這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之伸展樹(shù)詳解,本文對(duì)伸展樹(shù)(Splay Tree)的單旋轉(zhuǎn)操作、一字型旋轉(zhuǎn)、之字形旋轉(zhuǎn)區(qū)間操作等理論知識(shí)做了講解,并給出實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-08-08
  • C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)中棧的實(shí)現(xiàn)代碼

    C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)中棧的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C語(yǔ)言 數(shù)據(jù)結(jié)構(gòu)中棧的實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • C++深拷貝與淺拷貝的區(qū)別及應(yīng)用

    C++深拷貝與淺拷貝的區(qū)別及應(yīng)用

    這篇文章主要給大家介紹了關(guān)于C++深拷貝與淺拷貝區(qū)別及應(yīng)用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C語(yǔ)言中for循環(huán)問(wèn)題(一個(gè)小坑需注意)

    C語(yǔ)言中for循環(huán)問(wèn)題(一個(gè)小坑需注意)

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中for循環(huán)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03

最新評(píng)論