<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ## 概述 云風的`coroutine`是通過`ucontext`來控制程序運行時上下文的,我們來根據該庫提供的幾個接口,和一個demo來解釋協程的運行原理。如果不了解ucontext的,建議先了解`ucontxt` ## 環境 * [coroutine](https://github.com/cloudwu/coroutine) * Ubuntu16.04 * gcc * make * vscode 下載代碼 & 編譯 ``` $ git clone https://github.com/cloudwu/coroutine $ cd coroutine && make ``` ## 寫一個生產者和消費者的`demo` ``` //procus.c #include "coroutine.h" #include <stdio.h> #include <sys/types.h> struct args { int n; }; void product(struct schedule *S, void *arg) { struct args* a = (struct args*)arg; a->n = 1; while (a->n < 5) { a->n++; coroutine_yield(S); //flag 3 } } void consumer(struct schedule *S, int co, void *arg) { struct args* a = (struct args*)arg; while (coroutine_status(S,co)) { printf("get int %d\n", a->n); coroutine_resume(S,co); //flag 2 } printf("stop consumer\n"); } int main() { struct schedule * S = coroutine_open(); //flag 1 struct args arg; arg.n = 1; int co = coroutine_new(S, product, &arg); printf("co: %d\n", co); consumer(S, co, &arg); coroutine_close(S); return 0; } ``` 在Makefile中加入 ``` procus : procus.c coroutine.c gcc -g -Wall -o $@ $^ ``` ### 編譯&運行 ``` $ make procus $ ./procus co: 0 get int 1 get int 2 get int 3 get int 4 get int 5 stop consumer ``` ### 在vscode中調試 按下 F5, 生成`lunch.json`文件, 在文中加入下列行: ``` "program": "${workspaceFolder}/procus", ``` 在 `flag 1` `flag 2` `fllag 3`這三個地方打斷點。按一下F5,可以看到運行過程是 `flag 1`-> `flag 2`-> `fllag 3` 運行步驟: * coroutine_open: 打開調度器, 分配協程共享棧,`char stack[STACK_SIZE]`大小為 1M * coroutine_new: 創建一個協程,返回協程ID * coroutine_resume: 重新啟動一個協程 * coroutine_yield: 掛起一個協程 詳細講講`coroutine_resume`和`coroutine_yield`。 ### coroutine_resume 1.`coroutine_new`創建一個協程后,協程的狀態是`COROUTINE_READY`,調用`coroutine_resume`,協程狀態變為`COROUTINE_RUNNING`。 ``` getcontext(&C->ctx); C->ctx.uc_stack.ss_sp = S->stack; C->ctx.uc_stack.ss_size = STACK_SIZE; C->ctx.uc_link = &S->main; S->running = id; C->status = COROUTINE_RUNNING; C->ud = S->co[id]->ud; uintptr_t ptr = (uintptr_t)S; makecontext(&C->ctx, (void (*)(void)) mainfunc, 2, (uint32_t)ptr, (uint32_t)(ptr>>32)); swapcontext(&S->main, &C->ctx); ``` `coroutine_resume` 啟動狀態為`COROUTINE_READY`的協程: * 獲取當前`context` * 協程棧頂指向內存 `S->stack`,棧大小為`STACK_SIZE` * `C->ctx.uc_link `保存當前`context`結束后繼續執行的`context`記錄 * 修改協程運行狀態為`COROUTINE_RUNNING` * makecontext:設置函數指針`mainfunc`和堆棧到對應context保存的sp和pc寄存器中 * 保存當前`context`到`S->main`,切換`context`到`C->ctx` * 此時正在運行`mainfunc`函數 ,現在的上下文就是在 `(S->stack ,S->stack + STACK_SIZE)`運行的`C->ctx`,如果不懂這一步可以看[協程解析一(ucontext解析)](%E5%8D%8F%E7%A8%8B%E8%A7%A3%E6%9E%90%E4%B8%80(ucontext%E8%A7%A3%E6%9E%90).md) 查看`mainfunc`函數 ``` static void mainfunc(uint32_t low32, uint32_t hi32) { .... C->func(S,C->ud); _co_delete(C); S->co[id] = NULL; --S->nco; S->running = -1; } ``` * `mainfunc`函數運行的是`C->func`,運行完`C->func`之后就把該協程的運行棧的內存空間給釋放掉了。 * 運行完`mainfunc`函數后,context切換到`S->main`。 2.調用`coroutine_resume`,協程狀態變為`COROUTINE_RUNNING`, 運行`mainfunc`函數,運行到`C->func`, 實際上是在運行`product`函數,`product`函數調用了`coroutine_yield`,此時協程狀態變為`COROUTINE_SUSPEND`。保存此時協程的`context`-> `C-ctx`,切換協程上下文為`S->main`。此時運行時所在函數`coroutine_resume`標記1的位置。 ``` void coroutine_resume(struct schedule * S, int id) { ... switch(status) { case COROUTINE_READY: ... swapcontext(&S->main, &C->ctx); //標記1 break; case COROUTINE_SUSPEND: memcpy(S->stack + STACK_SIZE - C->size, C->stack, C->size); S->running = id; C->status = COROUTINE_RUNNING; swapcontext(&S->main, &C->ctx); //標記2 break; default: assert(0); } } ``` 3.此時相當于是回到了`customer`函數,此時協程狀態為`COROUTINE_SUSPEND`, 繼續循環調用`coroutine_resume`。 * 拷貝協程私有運行棧`C->stack`到共享棧 `S->stack`,大小為`C->size` * 設置此時正在運行的協程的協程ID,此時協程的狀態修改為`COROUTINE_RUNNING` * 保存此時`context`到`S->main`,切換`context`到`C->ctx`。`C->ctx`上運行的函數是`mainfunc`,也就是`product`函數。 ### coroutine_yield `C->func`函數指針指向的是`product`函數,`product`函數中調用了`coroutine_yield`,有以下代碼: ``` static void _save_stack(struct coroutine *C, char *top) { char dummy = 0; assert(top - &dummy <= STACK_SIZE); if (C->cap < top - &dummy) { free(C->stack); C->cap = top-&dummy; C->stack = malloc(C->cap); } C->size = top - &dummy; memcpy(C->stack, &dummy, C->size); } void coroutine_yield(struct schedule * S) { ... _save_stack(C,S->stack + STACK_SIZE); C->status = COROUTINE_SUSPEND; S->running = -1; swapcontext(&C->ctx , &S->main); } ``` 主要步驟 * 調用`_save_stack`函數,把協程指針和運行時棧底地址作為參數 1. `char dummy = 0;` 聲明一個變量,然后取地址,這個地址就是此時棧頂的地址。要理解這段代碼,要理解的幾個點: * `uncontext`的使用,`C->ctx.uc_stack.ss_sp = S->stack;`,`C->ctx.uc_stack.ss_size = STACK_SIZE;`這兩段代碼分配了此時協程可以使用的空間大小。 S->stack+STAACK_SIZE是棧底,S->stack是棧頂。 * 棧有先入后出的特性 * 棧的地址是從高到地分配的。 * `char dummy = 0;` 是一個分配在棧空間上的數據。此時 變量dummy的地址`&dummy`是協程的棧空間的棧頂地址。棧底地址-棧頂地址=`top-&dummy`,表示的是該協程所占用的空間大小。 2.`memcpy(C->stack, &dummy, C->size)`, 保存棧的數據到 `C->stack -> C->stack + C->size` * 修改協程的狀態為`COROUTINE_SUSPEND`, 設置此時運行的協程`id`為`-1`,掛起協程; * 保存當前的`context`到`C->ctx`, 切換當前的`context`為`S->main`。此時回到了 `標記2`,見上文。這樣就形成了閉環,直到`mainfunc`運行完畢,協程退出。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看