最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

協(xié)程vs線程

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

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

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

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

要實現(xiàn)一個協(xié)程,主要的問題是如何保存函數(shù)調(diào)用的上下文。之前在網(wǎng)上看到一篇博客coroutines in c,用一種非常簡潔的方式實現(xiàn)了這個保存上下文的功能。實現(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
}

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

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

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

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

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

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

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

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

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

因此問題還是有很多的:

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

總結(jié)

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

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

相關(guān)文章

  • C++11中std::declval的實現(xiàn)機制淺析

    C++11中std::declval的實現(xiàn)機制淺析

    這篇文章主要給大家介紹了關(guān)于C++11中std::declval實現(xiàn)機制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。
    2017-07-07
  • VC中CWinThread類以及和createthread API的區(qū)別分析

    VC中CWinThread類以及和createthread API的區(qū)別分析

    這篇文章主要介紹了VC中CWinThread類以及和createthread API的區(qū)別分析,較為詳細(xì)的講述了CWinThread類的原理,并以實例形式對AfxBeginThread函數(shù)的內(nèi)部實現(xiàn)進行了解釋說明,需要的朋友可以參考下
    2014-10-10
  • C語言中使用fopen()打開和操作文件的詳細(xì)方法指南

    C語言中使用fopen()打開和操作文件的詳細(xì)方法指南

    fopen是C語言庫函數(shù),open是系統(tǒng)調(diào)用,mmap是將大文件映射到內(nèi)存中使用,這篇文章主要給大家介紹了關(guān)于C語言中使用fopen()打開和操作文件的詳細(xì)方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • C語言求矩陣主對角線元素及副對角線元素之和

    C語言求矩陣主對角線元素及副對角線元素之和

    這篇文章主要介紹了C語言求矩陣主對角線元素及副對角線元素之和實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • c語言實現(xiàn)數(shù)組循環(huán)左移m位

    c語言實現(xiàn)數(shù)組循環(huán)左移m位

    這篇文章主要介紹了c語言實現(xiàn)數(shù)組循環(huán)左移m位,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++ 單鏈表的基本操作(詳解)

    C++ 單鏈表的基本操作(詳解)

    下面小編就為大家?guī)硪黄狢++ 單鏈表的基本操作(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng)

    大家好,本篇文章主要講的是用c語言實現(xiàn)《狼人殺》游戲發(fā)牌系統(tǒng),感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • 通過C語言判斷字符串是否為點分十進制的IP地址

    通過C語言判斷字符串是否為點分十進制的IP地址

    這篇文章主要為大家詳細(xì)介紹了如何通過C語言判斷字符串是否為點分十進制的IP地址,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03
  • C++中關(guān)于constexpr函數(shù)使用及說明

    C++中關(guān)于constexpr函數(shù)使用及說明

    這篇文章主要介紹了C++中關(guān)于constexpr函數(shù)使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++實現(xiàn)AVL樹的基本操作指南

    C++實現(xiàn)AVL樹的基本操作指南

    AVL樹是高度平衡的而二叉樹,它的特點是AVL樹中任何節(jié)點的兩個子樹的高度最大差別為1,下面這篇文章主要給大家介紹了關(guān)于C++實現(xiàn)AVL樹的相關(guān)資料,需要的朋友可以參考下
    2022-01-01

最新評論

长岭县| 张家川| 长兴县| 从江县| 临泽县| 绥滨县| 天长市| 加查县| 平阴县| 赤峰市| 科技| 黄龙县| 富源县| 始兴县| 许昌市| 榆社县| 峡江县| 平远县| 丹阳市| 儋州市| 腾冲县| 阿瓦提县| 兴安盟| 黄骅市| 静安区| 敦化市| 资溪县| 淮安市| 新和县| 德兴市| 新巴尔虎右旗| 康马县| 临高县| 钟山县| 顺义区| 福贡县| 米易县| 永川市| 封开县| 当涂县| 和平县|