近期想看看协程,对这个的详细实现不太了解。查了下,协程最常规的做法就是基于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系列函数的更多相关文章

  1. Kotlin协程基础

    开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 我们已经通过第一个例子学会了启 ...

  2. pyhon——进程线程、与协程基础概述

    一直以来写博客都是实用主义者,只写用法,没信心写原理,但是每一次写作业的过程都有一种掘地三尺的感觉,终于,写博客困难症重症患者经历了漫长的思想斗争,还是决定把从网上淘到的各种杂货和自己的总结放在一起, ...

  3. Lua的协程基础

    参考:Lua中的协同程序 coroutine   http.lua 协同程序(Coroutine): 三个状态:suspended(挂起,协同刚创建完成时或者yield之后).running(运行). ...

  4. [golang note] 协程基础

    协程概念 √ 协程通常称为coroutine,在golang中称为goroutine. √ 协程本质上是一种用户态线程,它不需要操作系统来进行抢占式调度,在实际实现中寄存在线程之中. √ 协程系统开销 ...

  5. 数据库 tcp协程实现并发 回调函数

    数据库 tcp协程实现并发 回顾 一.回顾 进程池,线程池,回调函数 # from gevent import monkey;monkey.patch_all() #补丁 from gevent im ...

  6. Unity协程基础用法

    //通过StartCoroutine()开始一个协程//通过StopCoroutine();关闭一个协程//通过StopAllCoroutines()方法来实现关闭所有协程void Start(){D ...

  7. 协程(Coroutines)实现fibonacci函数

    def fibonacci(): yield 1 yield 1 l=[1,1] while True: l=[l[-1],sum(l[-2:])] yield l[-1] def tribonacc ...

  8. Kotlin协程解析系列(上):协程调度与挂起

    vivo 互联网客户端团队- Ruan Wen 本文是Kotlin协程解析系列文章的开篇,主要介绍Kotlin协程的创建.协程调度与协程挂起相关的内容 一.协程引入 Kotlin 中引入 Corout ...

  9. Unity3d 协程、调用函数、委托

    (一)协程 开启方法:StartCoroutine("函数名"): 结束方法StopCoroutine("函数名"),StopAllCoroutines(); ...

随机推荐

  1. 使用python获取整月每一天的系统监控数据生成报表

    1.安装阿里开源监控工具tsar tsar官方网站 wget -O tsar.zip https://github.com/alibaba/tsar/archive/master.zip --no-c ...

  2. [BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 3591  Solved: 1780[Submit][Statu ...

  3. EF中使用Linq时First、FirstOrDefault、Single、SingleOrDefault几个方法的区别

    在使用EntityFramework开发时,.NET的System.Linq.Enumerable类为我们提供了许多Linq方法. 给大家分享一下关于First.FirstOrDefault.Sing ...

  4. (转)zeromq 安装

    http://youzifei.iteye.com/blog/1698237 zeromq 今天在安装zeromq的时候费了好大的力气才算装好 下面来回顾一下在linux安装zeromq的过程 首先 ...

  5. 非负整数可重集去重&排序+获得可重集的全排列的几种方法

    非负整数可重集O(n)去重并排序 可重集是指元素可重复的集合,对于在一定区间内的正整数集,比如[1,n],我们可以在不不使用任何额外空间(包括不使用O(1)的空间)的情况下,用O(n)的时间复杂度完成 ...

  6. hdu6166

    hdu6166 题意 给出一个有向图,选择 \(k\) 个点,问这 \(k\) 个点任意两点距离的最小值. 分析 按结点编号的二进制位,每次可以把所有点分到两个集合,那么求两个集合的点间的最短路即可( ...

  7. Xamarin XAML语言教程基本视图ContentViewg构架范围框架

    Xamarin XAML语言教程基本视图ContentViewg构架范围框架 ContentView视图基本上有三个作用,下面依次介绍. (1)范围框架:ContentView视图可以构建一个范围框架 ...

  8. 【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘

    [BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...

  9. [BZOJ 1912] patrol 巡逻

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1912 Algorithm: K=0:res=(n-1)*2   每条边恰好走2遍 K=1 ...

  10. 【网络流】【Dinic】【最大流】bzoj3396 [Usaco2009 Jan]Total flow 水流

    #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using ...