基础——Protothread协程库

    技术2022-07-11  131

    1. 几个概念

      (1) 进程

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

    直白地讲,进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程。

      (2) 线程

    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

    线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。

      (3) 协程

    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

    协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。

     

    2. c语言协程库

    实际上协程就是类函数一样的程序组件,你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。只不过子例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,又可以从上一个返回点继续执行,也就是说协程之间可以通过 yield 方式转移执行权,对称(symmetric)、平级地调用对方,而不是像例程那样上下级调用关系。当然 协程也可以上下级调用关系,这就叫非对称协程(asymmetric coroutines)。

    2.1 一段伪代码

    一个协程负责生产商品,并把商品加入队列,另一个负责从队列中取出商品并使用它。为了提高效率,你想一次增加或删除多个商品,可以如此逻辑:

    # producer coroutine loop while queue is not full create some new items add the items to queue yield to consumer # consumer coroutine loop while queue is not empty remove some items from queue use the items yield to producer

     

    C 依赖于一种叫做栈帧的例程调用,例程内部的状态量和返回值都保留在堆栈上,这意味着生产者和消费者相互之间无法实现平级调用。如果将每个协程的上下文(比如程序计数器)保存在其它地方而不是堆栈上,协程之间相互调用时,被调用的协程只要从堆栈以外的地方恢复上次出让点之前的上下文即可。C标准库给我们提供了两种协程调度原语:一种是 setjmp/longjmp,另一种是 ucontext 组件,它们内部(当然是用汇编语言)实现了协程的上下文切换。

    2.2 第三方协程库 protothreads

    特点:

    protothreads 整个库总共也就 5 个头文件,不需要链接加载,在任何平台上可移植;API 都是宏定义的,所以不存在调用开销;每个协程的空间开销是 2 个字节(一个 short 单位的“栈”!);

     

     

     

     

     

     

     

     

     

    Processed: 0.009, SQL: 12