文章目录

  • 项目介绍
    • 开发语言
    • 开发环境
    • 项目简介
    • 项目特点
    • 适用场景
    • 发布链接
  • 使用介绍
    • 上下文环境
    • 协程状态
    • 协程与调度器结构体
    • 接口
  • 示范用例
    • 使用协程实现一个TCP服务器

项目介绍

开发语言

C


开发环境

CentOS7、vim、gcc、gdb、git、MakeFile


项目简介

“协程”即用户态下的非抢占式的轻量级线程,是一种在程序开发中处理多任务的组件。
由于在C/C++中并没有引入协程这一概念,而大部分开源的库又过于重量,所以我基于ucontext组件实现了一个简单的协程库


项目特点

  • 用户态实现协程的调度切换,减少了内核切换的开销。
  • 非抢占式,用户自己实现调度,同一时间只能有一个协程在执行,由协程主动交出控制权。
  • 基于非对称(asymmetric)模式, 控制流更加简单,程序更加结构化。
  • 协程具有独立的栈,确保运行效率。

适用场景

协程主要适用于I/O密集型的场景,如示例中的TCP服务器。在传统的多路复用+多线程/多进程的做法,每并发一个进程/线程就会消耗内存,并且最严重的问题就是由系统来进行调度切换带来的严重损耗,而协程刚好能够解决这些问题。


发布链接

具体的实现请参考源代码
协程


使用介绍

上下文环境

对于上下文环境的切换可以使用很多方法

  • 汇编
  • C语言库函数setjmp, longjmp
  • glibc的ucontext组

我在这里使用的是ucontext组件,如果不了解这个组件的使用方法,可以参考我的另一篇博客
ucontext族函数的使用及原理分析

由于ucontext只支持posix,如果需要移植到windows,只需要将api换成fiber的即可


#define STACK_SIZE (1024 * 1024) //协程函数栈大小
#define COROUTINE_SIZE (1024)       //协程最大数量

协程状态

协程共设置了四种状态,READY, RUNNING, DEAD, SUSPEND。下图描述了所有状态即状态之间的转换关系。


协程与调度器结构体

typedef struct coroutine
{void* (*call_back)(struct schedule* s, void* args); //回调函数void* args; //回调函数的参数ucontext_t ctx; //协程的上下文char stack[STACK_SIZE]; //协程的函数栈enum State state;   //协程状态}coroutine;typedef struct schedule
{coroutine** coroutines; //协程数组int cur_id; //正在运行的协程下标int max_id; //数组中最大的下标ucontext_t main; //主流程上下文
}schedule;

接口

//创建协程序调度器
schedule* schedule_create();//创建协程, 并返回协程所处下标
int coroutine_create(schedule* s, void* (*call_back)(schedule*, void* ), void* args);//协程让出CPU,返回主流程上下文
void coroutine_yield(schedule* s);//恢复协程上下文
void coroutine_resume(schedule* s, int id);//运行协程
void coroutine_running(schedule* s, int id);//销毁协程调度器
void schedule_destroy(schedule* s);//判断协程调度器中的协程是否全部结束, 结束返回1, 没结束返回0
int schedule_finished(schedule* s);

示范用例

使用协程实现一个TCP服务器

思路图

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>#include "coroutine.h"
static int co_ids[COROUTINE_SIZE];void SetNoBlock(int fd)
{int flag = fcntl(fd, F_GETFL, 0);flag |= O_NONBLOCK;fcntl(fd, F_SETFL, flag);
}int socket_init()
{int lst_fd = socket(AF_INET, SOCK_STREAM, 0);if(lst_fd == -1){perror("socket.\n");exit(1);}int op = 1;setsockopt(lst_fd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op));struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9200);addr.sin_addr.s_addr = inet_addr("192.168.0.128");if(bind(lst_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){perror("bind.\n");exit(1);}if(listen(lst_fd, SOMAXCONN) < 0){   perror("listen.\n");exit(1);}return lst_fd;
}void accept_conn(int lst_fd, schedule *s, int* co_ids, void *(*call_back)(schedule *s, void *args))
{while(1){int new_fd = accept(lst_fd, NULL, NULL);//如果有新连接到来则创建一个协程来管理这个连接if(new_fd > 0){SetNoBlock(new_fd);int args[] = {lst_fd, new_fd};int cid = coroutine_create(s, call_back, args);if(cid >= COROUTINE_SIZE){perror("too many connections.\n");return;}co_ids[cid] = 1;coroutine_running(s, cid);}//如果当前没有连接,则切换至协程上下文中继续运行else{int i = 0;for(i = 0; i < COROUTINE_SIZE; i++){if(co_ids[i] == -1){continue;}coroutine_resume(s, i);}}}}void *handle(schedule  *s, void *args)
{int* arr = (int*)args;int cfd = arr[1];char buf[1024] = { 0 };while(1){memset(buf, 0, sizeof(buf));int ret = recv(cfd, buf, 1024, 0);if(ret < 0){//如果此时没有数据,则不再等待,直接切换回主流程coroutine_yield(s);}else if(ret == 0){//通信结束co_ids[s->cur_id] = -1;break;}else{printf("=> : %s\n", buf);if(strncasecmp(buf, "exit", 4) == 0){co_ids[s->cur_id] = -1;break;}send(cfd, buf, ret, 0);}}
}int main()
{static int co_ids[COROUTINE_SIZE];int lst_fd = socket_init();SetNoBlock(lst_fd);schedule* s = schedule_create();int i;for(i = 0; i < COROUTINE_SIZE; i++){co_ids[i] = -1;}accept_conn(lst_fd, s, co_ids, handle);schedule_destroy(s);
}

可以看到该服务器可以快速的响应多个连接

【项目介绍】协程——C语言实现的用户态非抢占式轻量级线程相关推荐

  1. 1个系统节拍 c语言_自己写的非抢占式嵌入式操作系统ATOS,全c语言,移植太......

    int main() { OS_CPU_SR cpu_sr; #if ((MBUS1_EN > 0) || (MBUS2_EN > 0)) CMBusComm param; #endif ...

  2. 项目 协程-实现非抢占式TCP服务器

    协程(Coroutines)是用户态下的非抢占式的轻量级线程,是一种在程序开发中处理多任务的组件 项目介绍 项目开发环境 Linux 项目开发语言及工具 C.vim.gcc.gdb.Makefile ...

  3. 线程库 c语言实现,130行C语言实现个用户态线程库——后续(一)

    130行C语言实现个用户态线程库--后续(1) ezCoroutine协程原型库只是个原型库,但是已经能够支持1000K以上数量的协程运行,而且是stackful模式.基本的对外接口有两类,一类是类似 ...

  4. FreeRTOS基础以及UIP之协程--C语言剑走偏锋

    在FreeRTOS中和UIP中,都使用到了一种C语言实现的多任务计数,专业的定义叫做协程(coroutine),顾名思义,这是一种协作的例程, 跟具有操作系统概念的线程不一样,协程是在用户空间利用程序 ...

  5. android room 线程,Android协程——RoomCoroutines-Go语言中文社区

    在Room2.1版本中提供了对协程的支持.Dao层的方法可以被suspend标记来确保他们在主线程中被执行.接下来,我们就来看看如何使用并为它写一个简单的单元测试. 为你的数据库加点suspendin ...

  6. 深入理解python.md_从python角度,理解进程,线程,协程.md-Go语言中文社区

    写在前面 文中有较多的内容为转载,尽量指出转载来源. 1 进程(process) 定义:进程是正在运行程序的实例. 如chrome 进程的三种状态: 就绪态 执行态 阻塞态 进程是基于计算机系统的异常 ...

  7. python 协程 多线程_python进阶之多线程(简单介绍协程)

    多线程 线程:实现多任务的另一种方式 一个进程中,也经常需要同时做多件事,就需要同时运行多个'子任务',这些子任务,就是线程 线程又被称为轻量级进程(lightweight process),是更小的 ...

  8. 协程 c语言,协程-C语言实现

    最近在学习lua的过程中发现lua居然有个东西叫协程(协同coroutine),虽然以前就听过这个概念,但没有结合实践的一些理解. 开始今天的文章前,首先需要学习下面几篇文章. Segment Fau ...

  9. java 协程框架_GitHub - yaozhang0105/dactor: Dactor是基于Java的轻量级同步异步统一处理框架,基于协程思想构建...

    DActor Introduction DActor框架基于协程思想设计,可同时支持同步和异步代码,简化在线异步代码的开发,用同步代码的思维来开发异步代码,兼顾异步代码的高并发.无阻塞和同步代码的易读 ...

最新文章

  1. LeetCode 228: Summary Ranges
  2. 【Live555】live555源码详解(八):testRTSPClient
  3. java.lang.OutOfMemoryError: PermGen space及其解决方法
  4. SQL*PLUS常用命令
  5. linux 定时任务
  6. itools下载链接被360警告:虚假招聘网站
  7. 每个程序员都应该知道的8个Linux命令
  8. 得到不小于x的最小的2的幂
  9. uefi多linux系统启动盘,DIY制作无需格BIOS+UEFI双启动U盘工具|支持syslinux+grub+boomgr+grub2多启动...
  10. vep文件如何转换mp4_如何将DVD的vob视频格式转换成mp4格式
  11. 简单地使用webpack进行打包,一些常见打包错误
  12. 【“互联网+”大赛华为云赛道】CloudIDE命题攻略:明确业务场景,快速开发插件
  13. asp.net MVC中怎样让LINQ Designer自动生成的类从别的类继承并调用其基类构造器?...
  14. python植树问题代码_BERT可以上几年级了?Seq2Seq“硬刚”小学数学应用题
  15. inDesign教程,如何将内容与参考线对齐?
  16. 两向量叉乘的计算公式_向量的数量积和向量积怎么算?
  17. win7引入node16版本
  18. 艺赛旗(RPA) 【操作列表】
  19. TUTK[Kalay][iOS]对接iOS TPNS推送流程
  20. RAMDISK 内存盘工具推荐

热门文章

  1. SpringBoot高级-检索-Elasticsearch简介安装
  2. SpringBoot整合 ActiveMQ、SpringBoot整合RabbitMQ、SpringBoot整合Kafka
  3. cookie和session常见问题
  4. 生命html文档,Web前端第一季(HTML)
  5. linux x86板级文件,Linux driver 板级文件跟踪一般方法
  6. 200905阶段一C++链表与继承特性
  7. 回调地狱解决方案之Promise
  8. vue axios 返回参数 响应参数
  9. 7分钟理解JS的节流、防抖及使用场景
  10. css 宽高自适应的div 元素 如何居中 垂直居中