技術文章: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語言協程的代碼細節 - 天天要聞

科技分類資訊推薦

阿里雲通義點金髮布DianJin-R1金融領域推理大模型 - 天天要聞

阿里雲通義點金髮布DianJin-R1金融領域推理大模型

近日,阿里雲通義點金團隊與蘇州大學攜手合作,在金融大語言模型領域推出了突破性的創新成果: DianJin-R1 。這款推理增強型金融大模型,融合了先進的技術和全面的數據支持,專為金融任務而設計。
曝iPhone 18 Pro內測屏下3D人臉識別:蘋果邁入單挖孔屏時代 - 天天要聞

曝iPhone 18 Pro內測屏下3D人臉識別:蘋果邁入單挖孔屏時代

快科技5月4日消息,博主數碼閑聊站爆料,iPhone 18 Pro和iPhone 18 Pro Max在測試屏下3D人臉識別,採用單挖孔屏形態。他還爆料,iPhone 18和iPhone 18 Air仍然是藥丸屏形態。眾所周知,從iPhone X開始,蘋果開啟了劉海屏時代,在這個劉海內,蘋果塞進了原深感攝像頭系統,實現了3D人臉識別,該系統包含了多個精密原件
三款7000元附近RTX 5070筆記本對壘,誰更讓你心動? - 天天要聞

三款7000元附近RTX 5070筆記本對壘,誰更讓你心動?

不得不說,RTX 50系列浪潮來得很快,這麼快就有多款產品在7000元附近了,選擇面很大。當然,這裡的功勞主要是補貼,沒補貼的話,這些本還在9000元高位,但有了補貼後,實際價格也是我們需要正視的。這次,我們就找到三款價格在7000元附近的RTX 5070筆記本,看看哪款讓你心動。第一款,是七彩虹隱星P16 Pro,原價8999元,到...
未來智能駕駛圖鑑:車路協同成主流,道路兩側也安上雷達! - 天天要聞

未來智能駕駛圖鑑:車路協同成主流,道路兩側也安上雷達!

新能源汽車風口下,智能駕駛成為起飛的豬。國內供應鏈發展也十分迅猛,現在10萬級的車也能體驗智駕,那麼在未來,智能駕駛會達到什麼樣的狀態呢?答案是「車路協同」。車端智能是基礎現在帶智駕功能的車都有一定的硬體基礎做支撐,比如毫米波雷達、攝像頭、激光雷達、晶元等,通過這些硬體,可以採集車輛周圍的環境信息和信...
「英偉達已向中國三家企業通報」 - 天天要聞

「英偉達已向中國三家企業通報」

據台灣《工商時報》網站5月3日報道,在針對中國市場的H20晶元遭美國政府禁售後,美國晶元大廠英偉達正加緊開發另一款符合美國出口規定的人工智慧(AI)晶元,以繼續保住其在中國的市場份額。
金舟投屏文件輸出目錄設置方法 - 天天要聞

金舟投屏文件輸出目錄設置方法

金舟投屏文件輸出目錄怎麼設置?跟著我來操作。1、 打開金舟投屏應用2、 在金舟投屏窗口,點擊菜單按鈕。3、 在彈出的下拉菜單中,選擇設置選項。4、 進入設置窗口後,選擇點擊文件選項。5、 在文件窗口裡,點擊輸出目錄按鈕,於彈出窗口選擇文件輸出路徑,例如:D:文件保存金舟投屏。6、 點擊關閉即可完成操作(9777180)...
E-鑽文件加密大師:輕鬆加密文件保護數據安全 - 天天要聞

E-鑽文件加密大師:輕鬆加密文件保護數據安全

對電腦文件加密,能保護個人隱私與商業機密,提升重要文件安全性。1、 把重要文件放入一個文件夾,進行加密保護。2、 開啟E-鑽文件加密大師;3、 點擊加密按鈕,選擇要加密的文件夾,然後單擊確定。4、 選擇加密強度與模式;5、 請再次輸入密碼,然後點擊確認。6、 點擊加密文件,輸入密碼後即可打開。(9777179)...