1)lua coroutine使用方法

http://timyang.net/lua/lua-coroutine/


coroutine_#includecoroutine_unix_02

co = coroutine.create(function ()         for i=1,10 do             print("co", i)             coroutine.yield()         end     end)  从主线程调用 coroutine.resume(co) 会依次打印1到10

View Code

说明

 LUA提供lua_newthread用于手工创建一个coroutine

 lua_yield用于挂起一个coroutine,不过该函数只能用于coroutine内部

 lua_resume用于启动一个coroutine,它可以用于coroutine没有运行时启动之,也可以用于coroutine挂起时重新启动

之。lua_resume在两种情况下返回:coroutine挂起或者执行完毕,否则lua_resume不返回

2)为什么要用coroutine?


    每个coroutine有自己私有的stack及局部变量。

    同一时间只有一个coroutine在执行,无需对全局变量加锁。

    顺序可控,完全由程序控制执行的顺序。而通常的多线程一旦启动,它的运行时序是没法预测的,因此通常会给测试所有的情况带来困难。所以能用coroutine解决的场合应当优先使用coroutine。


    协程最大的应用是取代回调机制,当需要异步执行的时候,启动一个协程,然后当前协程挂起去处理其他事务。异步结果完成后再继续执行,看上去是阻塞但实际上不会影响其他应用,另外一个作用是实现复杂跌代器。


3) 如何实现coroutine?

a)云风大师有一个实现 http://blog.codingnow.com/2012/07/c_coroutine.html

其主要原理是使用c posix函数setcontext来修改context(http://en.wikipedia.org/wiki/Setcontext)

b) 对应于windows下的函数是SetThreadContext

codeproject下有一个帖子Unix ucontext_t Operations on Windows Platforms基于windows api实现了setcontext函数

http://www.codeproject.com/Articles/4225/Unix-ucontext_t-Operations-on-Windows-Platforms

示例代码

coroutine_#includecoroutine_unix_02

/* testcontext.c : demo of ucontex_t operations */ #include <stdio.h> #include <stdlib.h> #include <ucontext.h>  ucontext_t auc,buc,mainuc;  void a() {     int i;      for (i = 0; i < 10; i++)     {         printf("a");         swapcontext(&auc, &buc);        /* switch to thread B */     }      printf("\nswitching to main\n");     swapcontext(&auc, &mainuc);         /* switch to main thread */ }  void b() {     int i;      for (i = 0; i < 10; i++)     {         printf("b");         swapcontext(&buc, &auc);        /* switch to thread A */     } }  int main(void) {     printf("start\n");                  /* main thread starts */      /* Set up context for thread A (Unix code, see manpages) */     getcontext(&auc);     auc.uc_stack.ss_size = 16 * 1024;      if ((auc.uc_stack.ss_sp = malloc(auc.uc_stack.ss_size)) == NULL)         perror("malloc"), exit(1);      auc.uc_stack.ss_flags = 0;     makecontext(&auc, a, 0);      /* Set up context for thread B */     getcontext(&buc);     buc.uc_stack.ss_size = 16 * 1024;      if ((buc.uc_stack.ss_sp = malloc(buc.uc_stack.ss_size)) == NULL)         perror("malloc"), exit(1);      buc.uc_stack.ss_flags = 0;     makecontext(&buc, b, 0);      /* Switch to A */     getcontext(&mainuc);           /* Save the context of main thread */     swapcontext(&mainuc, &auc);    /* Switch to thread A */      printf("\ndone\n");  /* Execution control returned to main thread */     return 0; } 运行结果 C:\>testcontext.exe start abababababababababab switching to main  done C:\>

View Code

c)context之类api的实现

在FreeBSD上你可以参考libc里的makecontext的实现:

/usr/src/lib/libc/i386/gen/makecontext.c


4)俺在github上的测试代码

​https://github.com/cutepig123/TestCoroutine/​