协程的介绍

协程(coroutine),意思就是“协作的例程”(co-operative routines),最早由Melvin Conway在1963年提出并实现。跟主流程序语言中的线程不一样,线程属于侵入式组件,线程实现的系统称之为抢占式多任务系统,而协程实现的多任务系统成为协作式多任务系统。线程由于缺乏yield语义,所以运行过程中不可避免需要调度,休眠挂起,上下文切换等系统开销,还需要小心使用同步机制保证多线程正常运行。而协程的运行指令系列是固定的,不需要同步机制,协程之间切换也只涉及到控制权的交换,相比较线程来说是非常轻便的。不过同一时刻可以有多个线程运行,但却只能有一个协程运行。
实际上协程的概念比线程还要早,按照 Knuth 的说法“子例程是协程的特例”,一个子例程就是一次子函数调用,那么实际上协程就是类函数一样的程序组件,你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。只不过子例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,又可以从上一个返回点继续执行,也就是说协程之间可以通过 yield 方式转移执行权,对称(symmetric)、平级地调用对方,而不是像例程那样上下级调用关系。当然 Knuth 的“特例”指的是协程也可以模拟例程那样实现上下级调用关系,这就叫非对称协程(asymmetric coroutines)。

setjmp.h

setjmp/longjmp  其实是C语言标准库中的内容,它被定义在<setjmp.h>头文件中,我认识的相当部分的人包括写过很多年C/C++的都表示没听过,并且他们在了解了一些setjmp的特性和功能之后还不以为然,说我又不会用到它;然而你们想过为什么标准库中会去实现一个相对这么怪异特性的语法支持?原因很简单,就是为了实现协程(coroutine),如果你一开始就给自己定位成协程的使用者,不关心它具体怎么实现的,甚至给自己定位成从不用协程,后面的内容你放心可以直接略过。
我们首先来看 setjmp/longjmp 这两个函数的定义。

int setjmp( jmp_buf _Buf );
void longjmp( jmp_buf _Buf, int _Value);

使用注意事项:
1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出

2、longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。
说白一点就是:在使用 setjmp 时,最常见的一个错误用法就是对它做封装,不应该封装在一个函数中。比如:

int try(breakpoint bp)
{
return setjmp(bp->jb);
} void throw(breakpoint bp)
{
longjmp(bp->jb,);
}

这样写并不会引起编译错误,但是极易容易发生运行时错误,因为setjmp的栈是在try函数中,而下一次调用longjmp的时候try函数可能已经不在栈中被清除了。
来个简单的例子:

#include <stdio.h>
#include <setjmp.h> jmp_buf buf;
void second()
{
printf("second\n");
longjmp(buf, );
}
void first()
{
second();
printf("first\n");
}
int coro_main()
{
if ( !(setjmp(buf)) )
{
first();
}
else
{
printf("main\n");
}
return ;
}

输出结果:

second
main

除此之外还有广为使用的C语言协程非标准库有 ucontext,据我所知ucontext应用更广泛一些,网上绝大多数 C 协程库也是基于 ucontext 组件实现的。有空下次再去研究研究它。。。

C语言标准库之setjmp的更多相关文章

  1. 附录二 C语言标准库

    上章回顾 数组和指针相同与不同 通过指针访问数组和通过数组访问指针 指针在什么时候可以加减运算 函数指针的申明和调用 函数数组和数组函数 git@github.com:Kevin-Dfg/Data-S ...

  2. Go语言标准库_输入/输出

    Go语言标准库_输入/输出 转载节选自<Go语言标准库> Reader 接口 type Reader interface { Read(p []byte) (n int, err erro ...

  3. GO语言标准库—命令行参数解析FLAG

    flag包是Go语言标准库提供用来解析命令行参数的包,使得开发命令行工具更为简单 常用方法 1.flag.Usage 输出使用方法,如linux下ls -h的帮助输出 2.flag.Type(参数名, ...

  4. Go语言标准库之JSON编解码

    Go语言标准库之JSON编解码 基本的类型 Go语言中的数据类型和JSON的数据类型的关系 bool -> JSON boolean float64 -> JSON numbers str ...

  5. Go语言标准库之time

    Go语言标准库之time 时间的格式化和解析 格式化 Format Go语言和其他语言的时间格式化的方式不同,Go语言格式化的方式更直观,其他的语言一般是yyyy-mm-dd package main ...

  6. C语言标准库 qsort bsearch 源码实现

    C语言是简洁的强大的,当然也有很多坑.C语言也是有点业界良心的,至少它实现了2个最最常用的算法:快速排序和二分查找. 我们知道,对于C语言标准库 qsort和 bsearch: a. 它是“泛型”的, ...

  7. Go语言标准库flag基本使用

    文章引用自   Go语言标准库flag基本使用 os.Args 如果你只是简单的想要获取命令行参数,可以像下面的代码示例一样使用os.Args来获取命令行参数. package main import ...

  8. Go语言标准库log介绍

    Go语言标准库log介绍 无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志一直都是非常重要的一个环节,我们也应该养成在程序中记录日志的好习惯. log Go语言内置的log包实现了简单的日志服 ...

  9. &lt;ctype.h&gt; C语言标准库

    ctype.h是C标准函数库中的头文件,定义了一批C语言字符分类函数(C character classification functions),用于測试字符是否属于特定的字符类别.如字母字符.控制字 ...

随机推荐

  1. 常见的web漏洞及其防范

    原文地址:http://blog.csdn.net/u013777676/article/details/52124298 一.SQL注入漏洞 SQL注入攻击(SQL Injection),简称注入攻 ...

  2. const指针与指向const的指针

    当使用带有const的指针时其实有两种意思.一种指的是你不能修改指针本身的内容,另一种指的是你不能修改指针指向的内容.听起来有点混淆一会放个例子上来就明白了.       先说指向const的指针,它 ...

  3. 聚类算法(二)--BIRCH

    BIRCH (balanced iterative reducing and clustering using hierarchies)(名字太长不用管了) 无监督,适合大样本的聚类方法.大多数情况只 ...

  4. Ansible Playbooks基本使用

    你将学到什么 如何使用playbook 如何编写playbook 如何使用roles PlayBook使用 基础环境 ### 64 位 Ubuntu 16.04 LTS,创建CentOS LXC容器w ...

  5. 洛谷P2700 逐个击破

    P2700 逐个击破 题目背景 三大战役的平津战场上,傅作义集团在以北平.天津为中心,东起唐山西至张家口的铁路线上摆起子一字长蛇阵,并企图在溃败时从海上南逃或向西逃窜.为了就地歼敌不让其逃走,毛主席制 ...

  6. 安居客scrapy房产信息爬取到数据可视化(上)-scrapy爬虫

    出发点 想做一个地图热力图,发现安居客房产数据有我要的特性.emmm,那就尝试一次好了~ 老规矩,从爬虫,从拿到数据开始... scrapy的配置 创建一个项目(在命令行下敲~): scrapy st ...

  7. 解决eclipse双击类名、选中类名出现假死或者非常慢的问题(取消Eclipse鼠标悬停和自定义快捷键)

    eclipse(MyEclipse)关闭鼠标移动提示代码功能和自定义快捷键代码提示设置的方法 eclipse(MyEclipse)关闭鼠标移动提示代码功能: eclipse(MyEclipse)--& ...

  8. ES6工作中常用知识点

    好久不动笔了 第一个知识点:import 和 export import导入模块.export导出模块 //全部导入 import people from './example' //有一种特殊情况, ...

  9. Ext3.1的一些使用讨论

    这里简单记录一下曾经的10个月使用Ext的工作模式. 前公司用的是 Ext 3.1,在2018/2019的今天,可以说是比较久远的技术了.处于大前端发展时代的我们,对其的诟病应该不少. 不过其中面向对 ...

  10. Qt学习之网络编程(一)

    一些说明 学了有一段时间的python了,小项目做了不少,最近由于项目需要,所以要回归老本行了,开始重点突击C++和qt.python的网络爬虫系列有时间就更吧. 获取本机网络信息 在网络应用中,经常 ...