最近在学习lua的过程中发现lua居然有个东西叫协程(协同coroutine),虽然以前就听过这个概念,但没有结合实践的一些理解。

开始今天的文章前,首先需要学习下面几篇文章。

Segment Fault例子:

#include

void ping();

void pong();

void ping(){

int a = 0;

printf("ping,addr of a = %p\n",&a);

pong();

}

void pong(){

int b = 0;

printf("pong,addr of b = %p\n",&b);

ping();

}

int main(int argc, char *argv[]){

ping();

return 0;

}

将上述代码编译运行,执行结果:

ping,addr of a = 0x7ffc456b2024

pong,addr of b = 0x7ffc456b2004

ping,addr of a = 0x7ffc456b1fe4

pong,addr of b = 0x7ffc456b1fc4

ping,addr of a = 0x7ffc456b1fa4

pong,addr of b = 0x7ffc456b1f84

ping,addr of a = 0x7ffc456b1f64

pong,addr of b = 0x7ffc456b1f44

ping,addr of a = 0x7ffc456b1f24

pong,addr of b = 0x7ffc456b1f04

ping,addr of a = 0x7ffc456b1ee4

pong,addr of b = 0x7ffc456b1ec4

ping,addr of a = 0x7ffc456b1ea4

pong,addr of b = 0x7ffc456b1e84

ping,addr of a = 0x7ffc456b1e64

pong,addr of b = 0x7ffc456b1e44

ping,addr of a = 0x7ffc456b1e24

pong,addr of b = 0x7ffc456b1e04

ping,addr of a = 0x7ffc456b1de4

pong,addr of b = 0x7ffc456b1dc4

ping,addr of a = 0x7ffc456b1da4

pong,addr of b = 0x7ffc456b1d84

ping,addr of a = 0x7ffc456b1d64

pong,addr of b = 0x7ffc456b1d44

ping,addr of a = 0x7ffc456b1d24

pong,addr of b = 0x7ffc456b1d04

ping,addr of a = 0x7ffc456b1ce4

pong,addr of b = 0x7ffc456b1cc4

ping,addr of a = 0x7ffc456b1ca4

pong,addr of b = 0x7ffc456b1c84

ping,addr of a = 0x7ffc456b1c64

pong,addr of b = 0x7ffc456b1c44

ping,addr of a = 0x7ffc456b1c24

pong,addr of b = 0x7ffc456b1c04

ping,addr of a = 0x7ffc456b1be4

pong,addr of b = 0x7ffc456b1bc4

ping,addr of a = 0x7ffc456b1ba4

pong,addr of b = 0x7ffc456b1b84

Segmentation fault (core dumped)

运行10几秒左右后,程序core dumped,无限递归调用,栈耗尽。可以看到a与b的地址每次调用都不相同。

#include

#include

#define MAX_COUNT (1<<30)

static ucontext_t uc[3];

static int count = 0;

void ping();

void pong();

void ping(){

int a = 10;

while(count < MAX_COUNT){

printf("ping %d,addr of a = %p\n", ++count,&a);

// yield to pong

swapcontext(&uc[1], &uc[2]); // 保存当前context于uc[1],切换至uc[2]的context运行

}

}

void pong(){

int b = 10;

while(count < MAX_COUNT){

printf("pong %d,addr of b = %p\n", ++count,&b);

// yield to ping

swapcontext(&uc[2], &uc[1]);// 保存当前context于uc[2],切换至uc[1]的context运行

}

}

char st1[8192];

char st2[8192];

int main(int argc, char *argv[]){

// initialize context

getcontext(&uc[1]);

getcontext(&uc[2]);

uc[1].uc_link = &uc[0]; //表示uc[1]运行完成后,会跳至uc[0]指向的context继续运行

uc[1].uc_stack.ss_sp = st1; // 设置新的堆栈

uc[1].uc_stack.ss_size = sizeof st1;

makecontext (&uc[1], ping, 0);

uc[2].uc_link = &uc[0]; //表示uc[2]运行完成后,会跳至uc[0]指向的context继续运行

uc[2].uc_stack.ss_sp = st2; // 设置新的堆栈

uc[2].uc_stack.ss_size = sizeof st2;

makecontext (&uc[2], pong, 0);

// start ping-pong

swapcontext(&uc[0], &uc[1]); // 将当前context信息保存至uc[0],跳转至uc[1]保存的context去执行

//swapcontext函数会将当前点的信息保存在uc[0]中,当然我们没有设置的话,默认的堆栈一定是主堆栈啦

return 0;

}

编译运行结果:

ping 332825,addr of a = 0x561022043b14

pong 332826,addr of b = 0x561022041b14

ping 332827,addr of a = 0x561022043b14

pong 332828,addr of b = 0x561022041b14

ping 332829,addr of a = 0x561022043b14

pong 332830,addr of b = 0x561022041b14

ping 332831,addr of a = 0x561022043b14

pong 332832,addr of b = 0x561022041b14

ping 332833,addr of a = 0x561022043b14

pong 332834,addr of b = 0x561022041b14

ping 332835,addr of a = 0x561022043b14

pong 332836,addr of b = 0x561022041b14

ping 332837,addr of a = 0x561022043b14

pong 332838,addr of b = 0x561022041b14

ping 332839,addr of a = 0x561022043b14

pong 332840,addr of b = 0x561022041b14

ping 332841,addr of a = 0x561022043b14

pong 332842,addr of b = 0x561022041b14

ping 332843,addr of a = 0x561022043b14

pong 332844,addr of b = 0x561022041b14

ping 332845,addr of a = 0x561022043b14

pong 332846,addr of b = 0x561022041b14

ping 332847,addr of a = 0x561022043b14

pong 332848,addr of b = 0x561022041b14

ping 332849,addr of a = 0x561022043b14

可以看到a b的地址每次都相同,而不是每次函数调用,使用新的栈地址空间。

#include

#include

#include

int main(int argc, char *argv[])

{

ucontext_t context;

getcontext(&context);

puts("Hello world");

sleep(1);

setcontext(&context);

return 0;

}

getcontext, setcontext - get or set the user context(man setcontext)

这个函数会不断地打印Hello,world。因为上面的getcontext函数将那个点的上下文信息保存到了context中,下面调用setcontext会返回到记录的点处继续执行,因此也就出现了不断地输出。

有了上面的一些理解,我们可以学习一些开源库。(按照代码量从低到高学习)

协程 c语言,协程-C语言实现相关推荐

  1. go语言协程和线程区别

    go语言协程和线程区别 一.线程和协程区别 主线程是一个物理线程,直接作用在 cpu 上的.是重量级的,非常耗费 cpu 资源. Go 主线程(/也可以理解成进程)一个 Go 线程上,可以起多个协程. ...

  2. python 协程_Python 协程与 Go 协程的区别(一)

    ? "Python猫" ,一个值得加星标的公众号 花下猫语:年关将近,不知各位过得怎样?我最近有些忙,收获也挺多,以后有机会分享下.吃饭时间,追了两部剧<了不起的麦瑟尔夫人& ...

  3. 干货 | 携程基于Quasar协程的NIO实践

    作者简介 Ryan,携程Java开发工程师,对高并发.网络编程等领域有浓厚兴趣. IO密集型系统在高并发场景下,会有大量线程处于阻塞状态,性能低下,JAVA上成熟的非阻塞IO(NIO)技术可解决该问题 ...

  4. python 协程可以嵌套协程吗_Python线程、协程探究(2)——揭开协程的神秘面纱...

    一.上集回顾 在上一篇中我们主要研究了python的多线程困境,发现多核情况下由于GIL的存在,python的多线程程序无法发挥多线程该有的并行威力.在文章的结尾,我们提出如下需求: 既然python ...

  5. 携程基于Quasar协程的NIO实践

    IO密集型系统在高并发场景下,会有大量线程处于阻塞状态,性能低下,JAVA上成熟的非阻塞IO(NIO)技术可解决该问题.目前Java项目对接NIO的方式主要依靠回调,代码复杂度高,降低了代码可读性与可 ...

  6. java 修改最大nio连接数_携程基于Quasar协程的NIO实践

    IO密集型系统在高并发场景下,会有大量线程处于阻塞状态,性能低下,JAVA上成熟的非阻塞IO(NIO)技术可解决该问题.目前Java项目对接NIO的方式主要依靠回调,代码复杂度高,降低了代码可读性与可 ...

  7. python 协程可以嵌套协程吗_Python | 详解Python中的协程,为什么说它的底层是生成器?...

    今天是Python专题的第26篇文章,我们来聊聊Python当中的协程. 我们曾经在golang关于goroutine的文章当中简单介绍过协程的概念,我们再来简单review一下.协程又称为是微线程, ...

  8. lua协程 unity_XLua 之 Lua 协程 与 Unity 协程互通

    前言: 最近在摸索用XLua 在 Unity 中进行全Lua 开发.然后就遇到了协程的问题.我想在 Lua 侧开启一个 Unity 的协程,该怎么做呢? 一开始我先去翻 XLua 的文档,我记得之前我 ...

  9. python携程多核_python 协程

    最近对Python中的协程挺感兴趣,这里记录对协程的个人理解. 要理解协程,首先需要知道生成器是什么.生成器其实就是不断产出值的函数,只不过在函数中需要使用yield这一个关键词将值产出.下面来看一个 ...

  10. python 协程可以嵌套协程吗_Python学习后有哪些方向可以选择?Python有什么好的学习方法吗?(附教程)...

    随着人工智能的发展,Python近两年也是大火,越来越多的人加入到Python学习大军,对于毫无基础的人该如何入门Python呢?这里整理了一些个人经验和Python入门教程供大家参考. 如果你是零基 ...

最新文章

  1. 【go】sdk + idea-plugin 开发工具安装
  2. UI+UE+UX+区别
  3. C++(STL):30 ---关联式容器map的operator[]和insert效率对比
  4. cad在布局怎么调比例_大神们都在用的9个CAD制图技巧,你会用几个?
  5. mysql手工注入imformation_mysql 简单手工注入
  6. 厚积薄发,丰富的公用类库积累,助你高效进行系统开发(10)---各种线程同步的集合类...
  7. mysql数据库密码修改
  8. 可视化 —— 在线图形绘制
  9. sklearn.metrics —— 混淆矩阵及其绘制、Accuracy/Precision/Recall/F1-score
  10. Linux用户管理基本配置命令运用1
  11. k2p 登录路由器shell失败_斐讯路由器无法进入路由器登录管理界面怎么办
  12. Linux获取电信超级密码,电信光猫-华为HG8245C获取超级管理员密码
  13. 2021泰迪杯数据分析技能赛A题:Python实现通讯产品销售和盈利能力分析(含原始数据)
  14. Xrm.WebApi 多对多关系处理
  15. c语言程序设计实践万年历,c语言程序设计万年历-20210408030342.docx-原创力文档
  16. Java飞机大战小游戏练习
  17. cad画不规则实体_cad画不规则曲线的方法步骤图
  18. 腾讯物联TencentOS tiny上云初探
  19. 210127 课内整理
  20. 区块链在改善网络安全方面的潜力?

热门文章

  1. JSK-390 计负均正【入门】
  2. CCF NOI1007 计算余数
  3. HDU2102 A计划【BFS】
  4. 命名 —— 函数、类的命名
  5. Java 并发 —— 读写锁(ReadWriteLock)
  6. 证明的思路 —— 数形结合
  7. 机器学习基础(十五)—— blending
  8. vmware 网络连接方式的说明
  9. 频率主义(Frequentism)与贝叶斯主义(Bayesianism)的哲学辨异与实践(Python仿真)
  10. pythonrequests证书_requests的ssl证书验证、身份认证、cert文件证书