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

科技分類資訊推薦

「英偉達已向中國三家企業通報」 - 天天要聞

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

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

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

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

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

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

Win7文件夾加密方法大全

如今,隱私的重要性日益凸顯。每個人都有自己的隱私,特別是在電腦中存儲了大量個人文件,其中一些是不想讓他人看到的重要資料。因此,我們需要為文件夾採取適當的保護措施。加密文件夾是最常用的方式之一,而加密方法多種多樣。這次我們將分享一種簡單易行的加密技巧,供大家參考使用。1、 在百度搜索強傑隱身俠下載,下載...
隱身俠的軟硬件區別 - 天天要聞

隱身俠的軟硬件區別

隱身俠是保障信息安全的利器,可用於保護和備份電腦、U盤、移動硬盤及加密雲盤中的重要文件與私密數據。它能有效防範因設備維修、丟失、被入侵或外借等情況導致的信息泄露或數據丟失風險,助您掌控信息資產,提升工作效率。此外,U型隱身俠還兼具普通U盤的存儲功能。1、 從使用方式來看,硬件版需將購入的隱身俠硬件PCKII插...
文件夾加密秘籍:使用加密軟件保護數據安全 - 天天要聞

文件夾加密秘籍:使用加密軟件保護數據安全

接下來,小編將1、 下載並安裝隱身俠應用查看2、 打開瀏覽器,搜索隱身俠,下載並安裝軟件,操作簡單,所示。3、 雙擊圖標開啟隱身俠4、 安裝軟件後,會提示重啟電腦,請重啟後再啟動隱身俠以使其生效,所示。5、 登錄賬號(若無賬號,註冊一個即可)。6、 請輸入賬號與密碼,參照下圖。7、 創建新的保險箱8、 登錄後,點擊...
隱身俠操作指南:簡單易懂的使用方法 - 天天要聞

隱身俠操作指南:簡單易懂的使用方法

隱身俠是一款保護電腦和移動存儲設備中重要文件與隱私信息的新一代信息安全產品。它能輕鬆加密硬盤、U盤等存儲設備中的數據,已通過多項權威認證。產品外形酷似小型U盤,不僅可作為普通U盤使用,還能充當電腦信息安全的防護工具,簡單易用,一分鐘學會操作,是保障個人電腦隱私安全的理想選擇。1、 首次設置使用2、 平常操...
金舟截圖軟件圖片輸出格式設置方法 - 天天要聞

金舟截圖軟件圖片輸出格式設置方法

1、 在右側彈出欄中,點擊程序設置選項。2、 在程序設置窗口,點擊圖片輸出格式按鈕,於彈出選項中選擇所需格式,例如JPEG。3、 點擊確定按鈕即可完成操作(9777181)...
解決Win10系統下隱身俠無法安裝的問題 - 天天要聞

解決Win10系統下隱身俠無法安裝的問題

隱身俠——您的信息保密專家。它能有效保護電腦、U盤、移動硬盤以及加密雲盤中的關鍵文件和機密數據,防範因設備維修、丟失、被盜用或黑客攻擊導致的信息泄露與損失風險,助您牢牢掌控核心資源,讓工作與生活更加安心無憂。此外,隱身俠本身也可作為普通U盤使用,兼具實用性與安全性。1、 請檢查您的Win10系統是否已啟用本...
新增旁路供電功能,一加 13 手機獲 ColorOS 15.0.0.821 升級 - 天天要聞

新增旁路供電功能,一加 13 手機獲 ColorOS 15.0.0.821 升級

IT之家 5 月 4 日消息,據IT之家讀者投稿,一加 13 手機現已獲推 PJZ110_15.0.0.821(CN01)版本更新,相應包體積為 1.62 GB,主要為手機帶來了旁路供電功能。旁路供電技術即手機直接由外部電源供電,此時電池則處於閑置狀態,既不充電也不放電,因此可以減少手機發熱,同時可以減少不必要的充放電循環,有助於延長電池的使...