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
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
示例代码

/* 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/



Powered by Jekyll and Theme by solid

本站总访问量