zoukankan      html  css  js  c++  java
  • 协程基础_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
    ");	//4
       printf("func1: swapcontext(&uctx_func1, &uctx_func2)
    ");	//5
       if (swapcontext(&uctx_func1, &uctx_func2) == -1) //切换回func2运行
    	   handle_error("swapcontext");
       printf("func1: returning
    ");	//7
    }
    
    static void
    func2(void)
    {
       printf("func2: started
    ");	//2
       printf("func2: swapcontext(&uctx_func2, &uctx_func1)
    ");	//3
       if (swapcontext(&uctx_func2, &uctx_func1) == -1)	//切换到func1运行
    	   handle_error("swapcontext");	
       printf("func2: returning
    ");	//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)
    "); //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
    "); //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) "); 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 "); 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 "); printf("func1: swapcontext(&uctx_func1, &uctx_func2) "); if (swapcontext(&uctx_func1, &uctx_func2) == -1) handle_error("swapcontext"); printf("func1: returning "); } void func2(void) { printf("func2: started "); printf("func2: swapcontext(&uctx_func2, &uctx_func1) "); if (swapcontext(&uctx_func2, &uctx_func1) == -1) handle_error("swapcontext"); printf("func2: returning "); }


    今天先弄到这.


    MAIL: xcl_168@aliyun.com
    BLOG: blog.csdn.net/xcl168


  • 相关阅读:
    数据库无限分级(分类表)
    从SQLserver中导出表数据到Access
    C# 对JS解析AJX请求JSON并绑定到html页面的一些心得
    高效的SQLSERVER分页查询(转载)
    Entity Framework自用的DataBase基类
    简单SVN使用方法
    CMD终端关于pip报错,scrapy报错的一种处理方法
    [原创]使用python对视频/音频文件进行详细信息采集,并进行去重操作
    Primer C++第五版 读书笔记(一)
    分享一个编程学习网站:https://github.com/justjavac/free-programming-books-zh_CN
  • 原文地址:https://www.cnblogs.com/yfceshi/p/6790555.html
Copyright © 2011-2022 走看看