coroutine
1)lua coroutine使用方法
http://timyang.net/lua/lua-coroutine/
co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end) 从主线程调用 coroutine.resume(co) 会依次打印1到10
说明
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
示例代码
/* 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:\>
c)context之类api的实现
在FreeBSD上你可以参考libc里的makecontext的实现:
/usr/src/lib/libc/i386/gen/makecontext.c
4)俺在github上的测试代码
https://github.com/cutepig123/TestCoroutine/