协程基础_context系列函数
近期想看看协程,对这个的详细实现不太了解。查了下,协程最常规的做法就是基于makecontext,getcontext,swapcontext这类函数在用户空间切换用户上下文。
所以在这通过样例代码尽量把context相关的函数弄清楚先。
#include <ucontext.h>
#include <stdio.h>
#include <stdlib.h> static ucontext_t uctx_main, uctx_func1, uctx_func2; #define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0) static void
func1(void)
{
printf("func1: started\n"); //4
printf("func1: swapcontext(&uctx_func1, &uctx_func2)\n"); //5
if (swapcontext(&uctx_func1, &uctx_func2) == -1) //切换回func2运行
handle_error("swapcontext");
printf("func1: returning\n"); //7
} static void
func2(void)
{
printf("func2: started\n"); //2
printf("func2: swapcontext(&uctx_func2, &uctx_func1)\n"); //3
if (swapcontext(&uctx_func2, &uctx_func1) == -1) //切换到func1运行
handle_error("swapcontext");
printf("func2: returning\n"); //6
} int
main(int argc, char *argv[])
{ //注意在实际中要注意stack大小,否则可能会出现溢出.
char func1_stack[16384];
char func2_stack[16384]; //获取当前进程/线程上下文信息,存储到uctx_func1中
if (getcontext(&uctx_func1) == -1)
handle_error("getcontext"); //uc_stack: 分配保存协程数据的堆栈空间
uctx_func1.uc_stack.ss_sp = func1_stack; //栈头指针
uctx_func1.uc_stack.ss_size = sizeof(func1_stack); //栈大小
uctx_func1.uc_link = &uctx_main; //协程兴许的context
makecontext(&uctx_func1, func1, 0); //依改动得到一个新的centext if (getcontext(&uctx_func2) == -1)
handle_error("getcontext");
uctx_func2.uc_stack.ss_sp = func2_stack;
uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
/* Successor context is f1(), unless argc > 1 */
//假设argc有传參数进来,则uc_link置为空.兴许代码将不再运行
uctx_func2.uc_link = (argc > 1) ? NULL : &uctx_func1;
makecontext(&uctx_func2, func2, 0); printf("main: swapcontext(&uctx_main, &uctx_func2)\n"); //1
//swapcontext(ucontext_t *oucp, ucontext_t *ucp)
// 进行上下文切换。将当前上下文保存到oucp中,切换到ucp
//将当前上下文保存到uctx_main, 并切换到uctx_func2
if (swapcontext(&uctx_main, &uctx_func2) == -1)
handle_error("swapcontext"); printf("main: exiting\n"); //8 : 如argc不为空则这不会运行.
exit(EXIT_SUCCESS);
}
样例执行结果:
suora:/test # ./co1 5
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
suora:/test # ./co1
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
func1: returning
main: exiting
从执行结果看,大致弄清这几个函数了,只是我对stack大小还是没弄清楚应当怎么估算,但我把这个样例再实现了下。
弄了个动态分配内存的试了试。
/*************************************************
Author: xiongchuanliang
Description: coroutine suora:/test # gcc -o co2 co2.c
suora:/test # ./co2
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
func1: returning
main: exiting
suora:/test # ./co2 3 5
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
suora:/test #
**************************************************/ #include <ucontext.h>
#include <stdio.h>
#include <stdlib.h> ucontext_t uctx_main, uctx_func1, uctx_func2; #define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0) #define CONTEXT_STACK (1024*64) // 64kB
typedef void (*context_func)(void); void func1(void);
void func2(void); int ctx_create(ucontext_t *ctx,
context_func func,
ucontext_t *ctx_link,
void *ss_sp,
size_t ss_size); int main(int argc, char *argv[])
{
if(ctx_create(&uctx_func1,func1,&uctx_main,
malloc(CONTEXT_STACK),CONTEXT_STACK) == 1)
return EXIT_FAILURE; if(ctx_create(&uctx_func2,func2,
(argc > 1) ? NULL : &uctx_func1 , //&uctx_func1
malloc(CONTEXT_STACK),CONTEXT_STACK) == 1)
{
free( uctx_func1.uc_stack.ss_sp );
return EXIT_FAILURE;
} printf("main: swapcontext(&uctx_main, &uctx_func2)\n"); if (swapcontext(&uctx_main, &uctx_func2) == -1)
handle_error("swapcontext"); free( uctx_func1.uc_stack.ss_sp );
free( uctx_func2.uc_stack.ss_sp ); printf("main: exiting\n");
exit(EXIT_SUCCESS);
} int ctx_create(ucontext_t *ctx,
context_func func,
ucontext_t *ctx_link,
void *ss_sp,
size_t ss_size)
{
if(getcontext(ctx) == -1)
{
handle_error("getcontext");
return 1;
}
ctx->uc_link = ctx_link;
ctx->uc_stack.ss_sp = ss_sp;
ctx->uc_stack.ss_size = ss_size;
ctx->uc_stack.ss_flags = 0; makecontext(ctx, func, 0);
return 0;
} void func1(void)
{
printf("func1: started\n");
printf("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
if (swapcontext(&uctx_func1, &uctx_func2) == -1)
handle_error("swapcontext");
printf("func1: returning\n");
} void func2(void)
{
printf("func2: started\n");
printf("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
if (swapcontext(&uctx_func2, &uctx_func1) == -1)
handle_error("swapcontext");
printf("func2: returning\n");
}
今天先弄到这.
MAIL: xcl_168@aliyun.com
BLOG: blog.csdn.net/xcl168
协程基础_context系列函数的更多相关文章
- Kotlin协程基础
开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 我们已经通过第一个例子学会了启 ...
- pyhon——进程线程、与协程基础概述
一直以来写博客都是实用主义者,只写用法,没信心写原理,但是每一次写作业的过程都有一种掘地三尺的感觉,终于,写博客困难症重症患者经历了漫长的思想斗争,还是决定把从网上淘到的各种杂货和自己的总结放在一起, ...
- Lua的协程基础
参考:Lua中的协同程序 coroutine http.lua 协同程序(Coroutine): 三个状态:suspended(挂起,协同刚创建完成时或者yield之后).running(运行). ...
- [golang note] 协程基础
协程概念 √ 协程通常称为coroutine,在golang中称为goroutine. √ 协程本质上是一种用户态线程,它不需要操作系统来进行抢占式调度,在实际实现中寄存在线程之中. √ 协程系统开销 ...
- 数据库 tcp协程实现并发 回调函数
数据库 tcp协程实现并发 回顾 一.回顾 进程池,线程池,回调函数 # from gevent import monkey;monkey.patch_all() #补丁 from gevent im ...
- Unity协程基础用法
//通过StartCoroutine()开始一个协程//通过StopCoroutine();关闭一个协程//通过StopAllCoroutines()方法来实现关闭所有协程void Start(){D ...
- 协程(Coroutines)实现fibonacci函数
def fibonacci(): yield 1 yield 1 l=[1,1] while True: l=[l[-1],sum(l[-2:])] yield l[-1] def tribonacc ...
- Kotlin协程解析系列(上):协程调度与挂起
vivo 互联网客户端团队- Ruan Wen 本文是Kotlin协程解析系列文章的开篇,主要介绍Kotlin协程的创建.协程调度与协程挂起相关的内容 一.协程引入 Kotlin 中引入 Corout ...
- Unity3d 协程、调用函数、委托
(一)协程 开启方法:StartCoroutine("函数名"): 结束方法StopCoroutine("函数名"),StopAllCoroutines(); ...
随机推荐
- Django-ContentType
背景:学位课.专题课.价格策略(每一种课程(学位课和专题课下可分为不同的种类的课程)在不同学习时间内的价格不同) 例如:如何将课程表与价格策略表关联起来: 用外键是可以将课程表和价格策略表关联起来的, ...
- elasticsearch中client.transport.sniff的使用方法和注意事项
https://blog.csdn.net/J_bean/article/details/79507559
- linux 设置svn钩子实现自动更新
一.svn安装设置 1.安装svn启动 yum install subversion 2.建个svn的根目录,因为项目不止一个 mkdir -p /home/svn/3.新建一个新的空的版本仓库(su ...
- WIN7下使用sublime text3替代arduino IDE(安装方法和所遇到的问题)
用了一段时间Arduino IDE,感觉比较简陋~~很多功能都没有~虽然不影响使用啦~(主要是启动速度有点慢...我的破笔记本….), 网上搜寻了下,发现sublime text有插件可以替代,这就比 ...
- Dart类
Dart中没有访问控制符,无论类还是方法默认都是public 1.构造函数 构造函数可以没有方法体,并且this可以直接在传参时直接对实例赋值 Bicycle(this.cadence, this.s ...
- (19)python扩展
当python程序遇到瓶颈时,可以考略扩展其他语言 例如:程序的某部分,需要高速度,或者与硬件交互时可以用到C语言.当其他语言有现成的程序,重新起来很麻烦时.有些功能用别的语言写更方便时 扩展语言有 ...
- POJ 1164 城堡问题【DFS/位运算/种子填充法/染色法】
1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#---#####---# 2 # # | ...
- 用JDBC操作MySQL——大量数据库操作时使用批处理提速
之前所有的操作由于数据量很小,所以没有进行批处理的优化,性能也没有出现明显的恶化,但是随着我用java处理数据量的大幅提高,频繁使用静态SQL语句的方法严重降低了处理效率,这里总结一下JDBC批处理的 ...
- 基于JS的event-manage事件管理库(一步一步实现)
关于文章 最近在提升个人技能的同时,决定把自己为数不多的沉淀记录下来,让自己理解的更加深刻,同时也欢迎各位看官指出不足之处. 随着node.js的盛行,引领着Javascript上天下地无所不能啊,本 ...
- Linux命令之kill
kill [-s signal | -p] [ --] pid… kill –l [signal] 终止指定进程.命令kill将指定的信号发送到指定的进程或进程组.如果没有指定信号,则发送SIGTER ...