C协程使用举例

本篇使用上一篇提供的接口,实现一个简单的协程调度框架.

基本思想是,创建一个调度器,用于将处于活动状态的协程调度运行,调度器维护着一个actived列表,

调用spawn创建协程时,将新建立的协程添加到活动列表中。

调用schedule将启动调度器主循环.

coro.h

复制代码
#ifndef _CORO_H
#define _CORO_H
#include <stdint.h>
#include "uthread.h"
struct coro
{
    struct coro *next;
    uthread_t ut;
    uint32_t id;
    start_fun st_fun;
    uint32_t is_end;
};
struct testarg
{
    struct coro *sche;
    struct coro *co;
};
void* yield(struct coro*,struct coro*,void *);
void* resume(struct coro*,struct coro*,void *);
struct scheduler
{
    struct coro *active;  //处于激活态的coro
    struct coro *self;
};
struct scheduler *scheduler_create();
//生成一个coro运行start_run
void spawn(struct scheduler*,void *stack,uint32_t stack_size,start_fun);
//调度coro运行
void schedule(struct scheduler*);
#endif
复制代码

coro.c

复制代码
#include "coro.h"
#include <stdlib.h>
#include <time.h>
void* yield(struct coro *from,struct coro *to,void *arg)
{
    return uthread_swtch(from->ut,to->ut,arg);
}
void* resume(struct coro *from,struct coro *to,void *arg)
{
    return uthread_swtch(from->ut,to->ut,arg);
}
static uint32_t g_index = 0;
static void* coro_start_fun(void *arg)
{
    struct testarg *_arg = (struct testarg *)arg;
    void *ret = _arg->co->st_fun(_arg);
    _arg->co->is_end = 1;
    return ret;
}
void spawn(struct scheduler *sche,void *stack,uint32_t stack_size,start_fun st_fun)
{
    uthread_t ut = uthread_create(stack,stack_size);
    struct coro *co = (struct coro*)malloc(sizeof(*co));
    co->ut = ut;
    co->st_fun = st_fun;
    co->id = ++g_index;
    //添加到激活队列中
    co->next = sche->active;
    co->is_end = 0;
    sche->active = co;
    uthread_make(co->ut,sche->self->ut,coro_start_fun);
}
struct scheduler *scheduler_create()
{
    struct scheduler *sche = (struct scheduler *)malloc(sizeof(*sche));
    sche->active = 0;
    sche->self = (struct coro*)malloc(sizeof(*sche->self));
    sche->self->ut = uthread_create(0,0);
    return sche;
}
void schedule(struct scheduler *sche)
{
    while(1)
    {
        if(sche->active)
        {
            struct coro *cur = sche->active;
            sche->active = 0;
            while(cur)
            {
                struct testarg arg = {sche->self,cur};
                resume(sche->self,cur,&arg);
                struct coro *tmp = cur->next;
                if(!cur->is_end)
                {
                    cur->next = sche->active;
                    sche->active = cur;
                    cur = tmp;
                }
                else
                {
                    uthread_destroy(&(cur->ut));
                    free(cur);
                }
                cur = tmp;
            }
        }
        else
            break;
    }
}
复制代码

test.c

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "uthread.h"
#include "coro.h"
void* fun(void *arg)
{
    struct testarg *_arg = (struct testarg *)arg;
    int i = 0;
    while(i<10)
    {
       printf("%d\n",_arg->co->id);
       yield(_arg->co,_arg->sche,0);
       ++i;
    }
    return 0;
}
int main()
{
    struct scheduler *sche = scheduler_create();
    spawn(sche,malloc(4096),4096,fun);
    spawn(sche,malloc(4096),4096,fun);
    spawn(sche,malloc(4096),4096,fun);
    spawn(sche,malloc(4096),4096,fun);
    schedule(sche);
    return 0;
}
复制代码