您的位置:首页 > 其它

windows 纤程(fiber) 实现的协程

2017-01-14 15:05 169 查看
参考云风的协程库实现:https://github.com/cloudwu/coroutine

云风的协程为 非对称的共享栈协程

以下为fiber实现的非对称协程:

环境:win7、VS2013

头文件: (coroutine.h)

#ifndef __COROUTINE__H__
#define __COROUTINE__H__

#define COROUTINE_DEAD     0
#define COROUTINE_READY    1
#define COROUTINE_RUNNING  2
#define COROUTINE_SUSPEND  3

typedef struct schedule schedule;
typedef void(*coroutine_func)(schedule *s, void *ud);

schedule *coroutine_open();
void coroutine_close(schedule *s);
int coroutine_new(schedule *s, coroutine_func *, void *ud);
void coroutine_resume(schedule *s, int id);
void coroutine_yield(schedule *s);
int coroutine_status(schedule *s, int id);
int coroutine_running(schedule *s);

#endif


源文件:(coroutine.c)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <assert.h>
#include "coroutine.h"

/* windows fiber版本的协程yield的时候直接切换到主协程(main),
而不是swapcontext的切换到上次运行协程,但最后达到的结果却一样
*/

// 默认容量
#define DEFAULT_CAP   8
// 堆栈大小
#define INIT_STACK    1048576 //(1024*1024)

typedef struct schedule schedule;
typedef struct coroutine coroutine;
typedef struct coroutine_para coroutine_para;

struct schedule
{
int  cap;     // 容量
int  conums;
int  curID;   // 当前协程ID
LPVOID    main;
coroutine **co;
};

struct coroutine
{
schedule  *s;
void      *ud;
int       status;
LPVOID    ctx;
coroutine_func func;
};

static int co_putin(schedule *s, coroutine *co)
{
if (s->conums >= s->cap)
{
int id = s->cap;
s->co = realloc(s->co, sizeof(coroutine *) * s->cap * 2);
memset(&s->co[s->cap], 0, sizeof(coroutine *) * s->cap);
s->co[s->cap] = co;
s->cap *= 2;
++s->conums;
return id;
}
else
{
for (int i = 0; i < s->cap; i++)
{
int id = (i + s->conums) % s->cap;
if (s->co[id] == NULL)
{
s->co[id] = co;
++s->conums;
return id;
}
}
}
assert(0);
return -1;
}

static void co_delete(coroutine *co)
{
//If the currently running fiber calls DeleteFiber, its thread calls ExitThread and terminates.
//However, if a currently running fiber is deleted by another fiber, the thread running the
//deleted fiber is likely to terminate abnormally because the fiber stack has been freed.
DeleteFiber(co->ctx);
free(co);
}

schedule *coroutine_open()
{
schedule *s = malloc(sizeof(schedule));
s->cap = DEFAULT_CAP;
s->conums = 0;
s->curID = -1;
s->co = malloc(sizeof(coroutine *) * s->cap);
memset(s->co, 0, sizeof(coroutine *) * s->cap);
s->main = ConvertThreadToFiberEx(NULL, FIBER_FLAG_FLOAT_SWITCH);
return s;
}

void coroutine_close(schedule *s)
{
for (int i = 0; i < s->cap; i++)
{
coroutine *co = s->co[i];
if (co) co_delete(co);
}
free(s->co);
s->co = NULL;
free(s);
}

void __stdcall coroutine_main(LPVOID lpParameter)
{
schedule* s = (schedule*)lpParameter;
int id = s->curID;
coroutine *co = s->co[id];

(co->func)(s, co->ud);

s->curID = -1;
--s->conums;
s->co[id] = NULL;
//co_delete(co);

SwitchToFiber(s->main);
}

int coroutine_new(schedule *s, coroutine_func *func, void *ud)
{
coroutine *co = malloc(sizeof(coroutine));
co->s = s;
co->status = COROUTINE_READY;
co->func = func;
co->ud = ud;
int id = co_putin(s, co);
co->ctx = CreateFiberEx(INIT_STACK, 0, FIBER_FLAG_FLOAT_SWITCH, coroutine_main, s);
co->status = COROUTINE_READY;

return id;
}

void coroutine_resume(schedule *s, int id)
{
assert(id >= 0 && id < s->cap);
if (id < 0 || id >= s->cap) return;
coroutine *co = s->co[id];
if (co == NULL) return;
switch (co->status)
{
case COROUTINE_READY:case COROUTINE_SUSPEND:
co->status = COROUTINE_RUNNING;
s->curID = id;
SwitchToFiber(co->ctx);
if (!s->co[id]) co_delete(co);
break;
default:
assert(0);
break;
}
}

void coroutine_yield(schedule *s)
{
int id = s->curID;
assert(id >= 0 && id < s->cap);
if (id < 0) return;

coroutine *co = s->co[id];
co->status = COROUTINE_SUSPEND;
s->curID = -1;

SwitchToFiber(s->main);
}

int coroutine_status(schedule *s, int id)
{
assert(id >= 0 && id < s->cap);
if (id < 0) return;
if (s->co[id] == NULL) {
return COROUTINE_DEAD;
}
return s->co[id]->status;
}

int coroutine_running(schedule *s)
{
return s->curID;
}


测试程序:(main.c)

#include "coroutine.h"

void test3(schedule *s, void *ud)
{
int *data = (int*)ud;
for (int i = 0; i < 3; i++)
{
printf("test3 i=%d\n",i);
coroutine_yield(s);
printf("yield co id = %d.\n", *data);
}
}

void coroutine_test()
{
printf("coroutine_test3 begin\n");
schedule *s = coroutine_open();

int a = 11;
int id1 = coroutine_new(s, test3, &a);
int id2 = coroutine_new(s, test3, &a);

while (coroutine_status(s, id1) && coroutine_status(s, id2))
{
printf("\nresume co id = %d.\n",id1);
coroutine_resume(s, id1);
//printf("resume co id = %d.\n", id2);
//coroutine_resume(s, id2);
}

int id3 = coroutine_new(s, test3, &a);
while (coroutine_status(s, id3))
{
printf("\nresume co id = %d.\n", id3);
coroutine_resume(s, id3);
}

printf("coroutine_test3 end\n");
coroutine_close(s);
}

int main()
{
coroutine_test();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  协程 fiber getcontext