博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现c协程
阅读量:5900 次
发布时间:2019-06-19

本文共 4825 字,大约阅读时间需要 16 分钟。

协程的概念就不介绍了,不清楚的同学可以自己google,windows和unix like系统

本身就提供了协程的支持,windows下叫fiber,unix like系统下叫ucontext.

在这里重复制造轮子,一是为了更清楚了解协程的实现,二是为了在windows和

unix like系统下都提供一套统一的协程接口.

首先介绍下接口,很简单,只有几个函数:

#ifndef _UTHREAD_H#define _UTHREAD_Htypedef void (*start_fun)(void *); typedef struct uthread* uthread_t;uthread_t uthread_create(void *stack,uint32_t stack_size);void uthread_destroy(uthread_t*);void uthread_run(uthread_t p,uthread_t u,start_fun st_fun,void *arg);void uthread_switch(uthread_t from,uthread_t to);#endif

下面主要介绍uthread_run:

uthread_run启动一个协程的运行,协程运行后会马上执行st_fun函数.
这里需要注意的地方是uthread_run的前两个参数,p和u,u是将被启动
的协程,而p是u的父协程.

如果p为空,则u执行完后将从uthread_run中返回,否则u执行完将调用

uthread_switch(u,p),将执行权交回给p.

uthead.c

#include 
#include "uthread.h"#include
#include
struct uthread{ //0:ebp,1:esp,2:ebx,3:edi,4:esi uint32_t reg[5]; uint32_t parent_reg[5]; struct uthread *parent;//如果_parent非空,则_start_fun结束后返回到_parent中 uint32_t __exit;//主函数调用完成设置 void *stack; start_fun _start_fun; void *start_arg; uint32_t stack_size;};uthread_t uthread_create(void *stack,uint32_t stack_size){ uthread_t u = calloc(1,sizeof(*u)); u->stack = stack; u->stack_size = stack_size; u->reg[0] = (uint32_t)stack+stack_size; u->reg[4] = (uint32_t)stack+stack_size; u->__exit = 0; return u;}extern void uthread_run1(uthread_t u,start_fun st_fun,void *arg);extern void uthread_run2(uthread_t p,uthread_t u,start_fun st_fun,void *arg);void uthread_run(uthread_t p,uthread_t u,start_fun st_fun,void *arg){ u->parent = p; if(u->parent) { uthread_run2(p,u,st_fun,arg); if(u->__exit) uthread_switch(u,p); } else { uthread_run1(u,st_fun,arg); }}void uthread_destroy(uthread_t *u){ free(*u); *u = 0;}

协程的启动和执行权切换无法用c语言完成,下面是用汇编代码实现的切换和启动函数:

switch.s

.align    4.globl    uthread_switch.globl    _uthread_switchuthread_switch:_uthread_switch: ##arg from to    movl 4(%esp), %eax     movl %ebp, 0(%eax)    movl %esp, 4(%eax)    movl %ebx, 8(%eax)    movl %edi, 12(%eax)    movl %esi, 16(%eax)    movl 8(%esp), %eax    movl 0(%eax), %ebp     movl 4(%eax), %esp    movl 8(%eax), %ebx    movl 12(%eax),%edi    movl 16(%eax),%esi    ret.align    4.globl    uthread_run1.globl    _uthread_run1uthread_run1:_uthread_run1: ##arg u_context    movl 4(%esp),%eax    movl %ebp,20(%eax) #save register    movl %esp,24(%eax)    movl %ebx,28(%eax)    movl %edi,32(%eax)    movl %esi,36(%eax)    movl 12(%esp),%ecx #get arg    movl 8(%esp),%edx #get st_fun    movl 0(%eax),%esp  #change stack    movl %esp,%ebp    pushl %eax    pushl %ecx     #push arg    call  *%edx    #call st_fun    popl  %eax    popl  %eax    movl 20(%eax),%ebp    #restore register    movl 24(%eax),%esp    movl 28(%eax),%ebx    movl 32(%eax),%edi    movl 36(%eax),%esi    movl $1,44(%eax)    ret.align    4.globl    uthread_run2.globl    _uthread_run2uthread_run2:#param p,u,start_fun,arg_uthread_run2:    movl 4(%esp),%eax  #get p    movl %ebp,0(%eax) #save register of p    movl %esp,4(%eax)    movl %ebx,8(%eax)    movl %edi,12(%eax)    movl %esi,16(%eax)    movl 8(%esp),%eax  #get u    movl 16(%esp),%ecx #get arg    movl 12(%esp),%edx #get st_fun    movl 0(%eax),%esp  #change stack    movl %esp,%ebp    pushl %eax    pushl %ecx     #push arg    call  *%edx    #call st_fun    popl  %eax    popl  %eax    movl $1,44(%eax)    movl 40(%eax),%eax   #get parent    movl 0(%eax),%ebp    #restore register    movl 4(%eax),%esp    movl 8(%eax),%ebx    movl 12(%eax),%edi    movl 16(%eax),%esi    ret

test.c

#include 
#include
#include
#include "uthread.h"struct pair{ uthread_t self; uthread_t other;};void fun2(void *arg){ int i = 0; struct pair *p = (struct pair*)arg; printf("fun2\n"); uthread_switch(p->self,p->other); printf("fun2 end\n");}void fun1(void *arg){ int i = 0; struct pair *p = (struct pair*)arg; char *s = malloc(4096); uthread_t u2 = uthread_create(s,4096); struct pair _p = {u2,p->self}; uthread_run(p->self,u2,fun2,&_p); printf("here\n"); uthread_switch(p->self,u2); printf("fun1 end\n");}int main(){ char *s = malloc(4096); uthread_t u1 = uthread_create(s,4096); struct pair p = {u1,0}; uthread_run(0,u1,fun1,&p); printf("return here\n"); return 0;}

 更新:

调整了协程接口,支持在uthread_swtch间传递和返回数据,使用方式更接近lua coroutine

接口如下:

#ifndef _UTHREAD_H#define _UTHREAD_Htypedef void* (*start_fun)(void *); typedef struct uthread* uthread_t;uthread_t uthread_create(void *stack,uint32_t stack_size);void uthread_destroy(uthread_t*);void uthread_make(uthread_t u,uthread_t p,start_fun st_fun);void* uthread_swtch(uthread_t from,uthread_t to,void *arg);#endif

 

新代码地址:

 

转载于:https://www.cnblogs.com/sniperHW/archive/2012/06/19/2554574.html

你可能感兴趣的文章
Activity跳转时生命周期跟踪
查看>>
artemplate使用
查看>>
Tableau 地图
查看>>
【Flash】spi-flash规范分析
查看>>
设计数据库时记
查看>>
【dfs or 最短路】【HDU1224】【Free DIY Tour】
查看>>
iOS 10 开发适配系列 之 权限Crash问题
查看>>
iOS - OC NSSet 集合
查看>>
Test Kitchen 0.7.0支持在OpenStack上对Opscode Chef进行集成测试
查看>>
8.9整理笔记待续
查看>>
集算器之五:序表
查看>>
php中io操作!
查看>>
linux根分区满
查看>>
Linux系统服务器 GNU Bash 环境变量远程命令执行漏洞修复命令
查看>>
Jpush推送模块
查看>>
Linux之部署前后端分离项目
查看>>
js的数组去重
查看>>
Python 工具包 werkzeug 初探
查看>>
(原创)面向对象的系统对接接口编写。第2篇
查看>>
List接口
查看>>