【C協程】ucontext入解

來源:互聯網
上載者:User

In  a  System V-like environment, one has the type ucontext_t defined in <ucontext.h> and the four functions get-context(2), setcontext(2), makecontext() and swapcontext() that allow user-level context switching between multi-ple threads of control within a process.

在系統V環境中,我們可以通過getcontext,setcontext,makecontext,swapcontext函數族,在單進程中實現使用者態內容相關的切換。


一、認識ucontext

首先我們來認識一下這個結構中的文鍵變數,結構如下,需要關注到的是uc_stack,以及uc_link,uc_stack指向環境切換需要儲存的棧空間,需要使用者指派。uc_link指向當時上下文執行函數成功退出後,指定啟用的上下文,如果為uc_link為NULL時則直接退出。

typedef struct ucontext{    unsigned long int uc_flags;    struct ucontext *uc_link;    stack_t uc_stack;    mcontext_t uc_mcontext;    __sigset_t uc_sigmask;    struct _fpstate __fpregs_mem;} ucontext_t;


二、認識函數族

int getcontext(ucontext_t *ucp);
getcontext(2) gets the current context of the calling process, storing it in the ucontext struct  pointed  to  by ucp.

getcontext把當前的上下文儲存在ucp中


int setcontext(const ucontext_t *ucp);
setcontext(2)  sets  the  context of the calling process to the state stored in the ucontext struct pointed to by ucp. The struct must either have been created by getcontext(2) or have been passed as the third parameter of  the sigaction(2) signal handler.

setcontext把當前進程恢複到ucp指標指向的上下文,ucp必須由getcontext建立


void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);

The  makecontext()  function  modifies  the  context pointed to by ucp (which was obtained from a call to getcon-text(2)).  Before invoking makecontext(), the caller must allocate a new stack for this context  and  assign  its address to ucp->uc_stack, and define a successor context and assign its address to ucp->uc_link.

When  this  context  is  later  activated (using setcontext(2) or swapcontext()) the function func is called, and passed the series of integer (int) arguments that follow argc; the caller must specify the number of these  argu-ments in argc.  When this function returns, the successor context is activated.  If the successor context pointer is NULL, the thread exits.

makecontext修改ucp指標指向的上下文,在調用makecontext之前,必須為ucp對象分配一個新棧並賦為ucp->uc_stack,同時定義一個成功返回後恢複的上下文並把地址賦給ucp->uc_link。當ucp被啟用後(通過setcontext或swapcontext啟用),func函數會被調用,並把一系統參數傳凝視給func函數。當func函數返回原來,uc_link會被啟用,uc_link為NULL時,線程退出。


int swapcontext(ucontext_t *oucp, ucontext_t *ucp);
The swapcontext() function saves the current context in the structure pointed to by oucp, and then activates  the context pointed to by ucp.

swapcontext把當前上下文儲存在oucp中,並啟用ucp。


三、樣本

3.1 MAN手冊樣本

#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 voidfunc1(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");}    static voidfunc2(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");}    intmain(int argc, char *argv[]){    char func1_stack[16384];    char func2_stack[16384];    if (getcontext(&uctx_func1) == -1)        handle_error("getcontext");    uctx_func1.uc_stack.ss_sp = func1_stack;    uctx_func1.uc_stack.ss_size = sizeof(func1_stack);    //uctx_func1.uc_link = &uctx_func2;    uctx_func1.uc_link = &uctx_main;    makecontext(&uctx_func1, func1, 0);    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 */    uctx_func2.uc_link = (argc > 1) ? NULL : &uctx_func1;    makecontext(&uctx_func2, func2, 0);    printf("main: swapcontext(&uctx_main, &uctx_func2)\n");    if (swapcontext(&uctx_main, &uctx_func2) == -1)        handle_error("swapcontext");    printf("main: exiting\n");    exit(EXIT_SUCCESS);}
輸出如下 :

func2: startedfunc2: swapcontext(&uctx_func2, &uctx_func1)func1: startedfunc1: swapcontext(&uctx_func1, &uctx_func2)func2: returningfunc1: returningmain: exiting


3.2 生產者消費者

#include <ucontext.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>static ucontext_t uc_loop, uc_main, uc_consume, uc_produce;static int ci, pi, loop;static void cb_consume(){    printf("consume %d\n", ci);    ci++;    sleep(1);}static void cb_produce(){    printf("produce %d\n", pi);    pi++;}int main(void){    char  consume_stack[1024], produce_stack[1024];    getcontext(&uc_loop);    getcontext(&uc_produce);    uc_produce.uc_stack.ss_sp = produce_stack;    uc_produce.uc_stack.ss_size = sizeof(produce_stack);    uc_produce.uc_link = &uc_consume;    makecontext(&uc_produce, cb_produce, 0);    printf("finish make produce\n");    getcontext(&uc_consume);    uc_consume.uc_stack.ss_sp = consume_stack;    uc_consume.uc_stack.ss_size = sizeof(consume_stack);    uc_consume.uc_link = &uc_main;    makecontext(&uc_consume, cb_consume, 0);    printf("finish make consume\n");    printf("swap main to produce\n");    swapcontext(&uc_main, &uc_produce);    printf("swap back to main\n");    sleep(1);    loop++;    if (loop < 2) setcontext(&uc_loop);    return 0;}

輸出如下:

finish make producefinish make consumeswap main to produceproduce 0consume 0swap back to mainfinish make producefinish make consumeswap main to produceproduce 1consume 1swap back to main



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.