技術文章:C語言協程的代碼細節

2022年10月08日01:57:07 科技 1901

“協程”(coroutine),就是把Linux epoll異步IO機制通過長跳轉(long jmp)封裝起來,形成一個在用戶看來“連續的”流程。

所有操作系統的異步IO,都分為啟動函數回調函數

Linux為例,啟動函數負責往epoll框架里添加讀寫事件。

事件觸發之後,再通過回調函數去進行下半部的處理。

整個事件處理過程,與Linux內核里的中斷處理差不多。

一個完整的IO流程需要回調好幾次,而且讀代碼時到處查找回調函數哪裡設置的

甚至,有的程序員中途修改回調函數的指針[捂臉]

C的函數指針比C++的虛函數“靈活”的地方是,C++的虛函數表在編譯時固定了,但C的函數指針可以在運行時修改(它就是個普通變量)。

然後,就真有人半截里修改它,讓代碼的可讀性急劇下降。

再然後,就出現了coroutine,看上去至少是同步的了。

程序流程在一個函數里跳轉,就是普通的goto語句

程序流程在2個函數的半截里跳轉,就是長跳轉(long jmp)。

協程的原理如下:

1,當某個文件描述符需要IO等待的時候,通過長跳轉回到epoll的主框架函數,讓其他的IO可以運行。

2,當這個文件描述符的IO再次就緒之後,再通過長跳轉從主框架函數跳回來,接着上次的位置繼續運行:

這個位置,是函數上一次放棄運行的位置,它是函數內的某個點。

技術文章:C語言協程的代碼細節 - 天天要聞

在函數的半截里放棄CPU之後還能回來,就需要保存函數的運行上下文:信息、寄存器信息。

保存到哪裡?

只能保存到上,因為棧和寄存器都會隨着代碼的運行而不斷地覆蓋,只有堆是受用戶控制的。

技術文章:C語言協程的代碼細節 - 天天要聞

用戶測試代碼

上圖是“用戶代碼”,雖然兩個函數__async_connect()和__async_write()的內部是異步執行的,但它們都在一個函數_async_test()里,整個流程看上去是同步的。

技術文章:C語言協程的代碼細節 - 天天要聞

__async_connect()函數,上半部

__async_connect()分為上半部和下半部,以__asm_co_task_yield()為分隔點。

上半部調用異步的connect(),下半部調用getsockopt()讀取結果。

為了避免阻塞線程,需要在異步connect()之後讓出CPU,讓主框架函數可以做別的

這個讓出CPU的函數__asm_co_task_yield(),是“協程庫”的關鍵。

它讓出了CPU之後,在事件觸發之後再次恢復運行:這時函數__asm_co_task_yield()才會返回,然後接着運行下圖的代碼。

技術文章:C語言協程的代碼細節 - 天天要聞

__async_connect()函數,下半部

當異步connect()成功時,getsockopt()獲取的錯誤碼err是0。

技術文章:C語言協程的代碼細節 - 天天要聞

__async_write()函數

__async_write()函數的流程與__async_connect()類似,也是在文件描述符變得不可寫時放棄CPU,等待下次可寫時再恢復運行。

技術文章:C語言協程的代碼細節 - 天天要聞

epoll主框架函數

epoll的主框架函數是一個while循環:使用epoll_wait()系統調用去監控事件的觸發。

它會同時處理IO事件定時器

定時器的精度受限於epoll_wait()的等待時間

技術文章:C語言協程的代碼細節 - 天天要聞

epoll主框架函數

__scf_co_task_run(),可以讓“協程任務”首次運行,或者再次恢復運行。

技術文章:C語言協程的代碼細節 - 天天要聞

_scf_co_task_run()函數

這個函數只是調用了__asm_co_task_run(),具體的長跳轉彙編里實現。

因為長跳轉涉及到細緻的內存控制,只能用彙編實現。

運行結果:

要在本機上用命令nc -vv -l 2000當服務端。

技術文章:C語言協程的代碼細節 - 天天要聞

打印的日誌,是長跳轉時的棧信息的變化

技術文章:C語言協程的代碼細節 - 天天要聞

兩個彙編函數的大概功能,如下面的3張圖。

細節就不說了,這種代碼,時間久了連作者都快看不懂了[捂臉]

技術文章:C語言協程的代碼細節 - 天天要聞

技術文章:C語言協程的代碼細節 - 天天要聞

技術文章:C語言協程的代碼細節 - 天天要聞

科技分類資訊推薦

Pura80Pro與Mate70Pro,誰是華為旗艦更優解?一文看懂 - 天天要聞

Pura80Pro與Mate70Pro,誰是華為旗艦更優解?一文看懂

每當華為旗艦新機臨近發布節點,科技圈的焦點就會轉移到“新舊旗艦”之間的對比上,這也是許多消費者最關注的問題之一,比如即將在6月11日發布的「Pura80 Pro」以及已經上市半年的「Mate70 Pro」,一款是華為在影像領域進一步突破的全
周鴻禕:準備幹掉360整個市場部,每年能省幾千萬 - 天天要聞

周鴻禕:準備幹掉360整個市場部,每年能省幾千萬

6月6日晚,360集團創始人、董事長周鴻禕在其個人自媒體賬號發文稱,“我準備幹掉360整個市場部,這樣一年可以給公司省下幾千萬。”他表示從當天起,要做一個挑戰,一個人完成一場完整的新產品發布會。“聽起來像天方夜譚,但這次我準備動真格的了。”周鴻禕稱,過去做一個產品發布會,需要市場部幾十號人,忙活大半個月,費...
新疆低空經濟加力擴容 - 天天要聞

新疆低空經濟加力擴容

天山網/新疆日報記者 馬伊寧不久前,“阿勒泰低空飛行服務保障中心”及“布爾津、富蘊低空飛行服務保障站”投入運營。作為擁有世界級旅遊資源的區域,阿勒泰地區正構建覆蓋北疆的低空飛行服務網絡,為通用航空、無人機物流、低空旅遊等業態提供全鏈條服務保
特斯拉“擎天柱”人形機器人項目負責人宣布離職 - 天天要聞

特斯拉“擎天柱”人形機器人項目負責人宣布離職

中新網6月7日電(吳家駒)綜合外媒報道,特斯拉“擎天柱”(Optimus)人形機器人項目負責人米蘭·科瓦奇(Milan Kovac)周五表示,他將離開公司。 科瓦奇在X平台上發文稱,“我不得不做出一生中最艱難的決定,我將離開我的職位。我離家太久了,需要花更多的時間和國外的家人在一起。”科瓦奇稱,這是“唯一的原因,與其他任何事情...
512GB售價2039元!3840HZ+7550mAh+極窄直屏,紅米手機價格親民了 - 天天要聞

512GB售價2039元!3840HZ+7550mAh+極窄直屏,紅米手機價格親民了

卡頓可以說是很多消費者使用手機時遇到的最為頭疼的情況,好在就如今新發布的機型就算是在長時間的使用之下,也並不會讓你出現如此的情況,這就比如說紅米Turbo 4 Pro這款機型就是如此,這款機型不僅性能狂飆、續航超長,更有旗艦級配置和貼心細節