技术文章: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,主要为手机带来了旁路供电功能。旁路供电技术即手机直接由外部电源供电,此时电池则处于闲置状态,既不充电也不放电,因此可以减少手机发热,同时可以减少不必要的充放电循环,有助于延长电池的使...