您的位置:首页 > 其它

协程基础_context系列函数

2014-10-09 21:10 281 查看
  最近想看看协程,对这个的具体实现不太了解,查了下,协程最常规的做法就是基于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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息