lua coroutine & skynet

1.lua中的协程

thread type

用于创建协程(coroutines),跟OS的thread不是一个概念

Python则不同,Python的线程就是OS原生线程;不过stackless和pypy的微线程跟这个概念差不多

Coroutines

又名collaborative multithreading(协作多线程)

每个协程是一个独立的线程(lua thread, not os thread),当前协程只有在显式调用yield时才会挂起

coroutine.create(..)创建协程,参数:协程要执行的main函数;返回值:thread对象,指向协程

coroutine.resume(..)启动/恢复协程,第一个参数是thread对象

启动时其他参数传递给协程对应的main函数

恢复时其他参数赋值给中断时yield赋值的对象

coroutine.yield(..)挂起协程,导致coroutine.resume()立即返回,返回值:true+yield的参数;

下次resume时从这个点恢复执行

The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield returning any extra arguments passed to coroutine.resume.

coroutine.wrap(..)创建协程,参数:协程要执行的main函数;返回值:function,调用function则等效于coroutine.resume(..),参数被传递给协程main函数

跟cotoutine.resume(..)的主要区别是不捕获错误,错误会向上传播,返回值没有第一个boolean.

其实说白了就是对main函数做了一个包装,不用显示的调用resume,可以差不多像原函数一样使用

协程结束:

1.协程执行的函数终结,这种情况coroutine.resume()返回true+协程函数返回值

2.协程执行的函数出现无保护的错误,这种情况coroutine.resume()返回false+错误信息

EXAMPLE:

[dongsong@localhost skynet]$ lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> =coroutine
table: 0x113f600
> for k,v in pairs(coroutine) do print(k,v) end
resume  function: 0x113f830
yield   function: 0x113f9b0
status  function: 0x113f8f0
wrap    function: 0x113f950
create  function: 0x113e2e0
running function: 0x113f890

[dongsong@localhost lua-study]$ cat coroutine.lua 
function foo (a)
	print("foo", a)
	return coroutine.yield(2*a)                 --resume returned: true 4
end

co = coroutine.create(function (a,b)
	print("co-body", a, b)
	local r = foo(a+1)
	print("co-body", r)
	local r, s = coroutine.yield(a+b, a-b)      --resume returned: true 11 -9
	print("co-body", r, s)
	return b, "end"                             --resume returned: true 10 end
end)

print("main", coroutine.resume(co, 1, 10))      --main true 4
print("main", coroutine.resume(co, "r"))        --main true 11 -9
print("main", coroutine.resume(co, "x", "y"))   --main true 10 end
print("main", coroutine.resume(co, "x", "y"))   --main false cannot resume dead coroutine
[dongsong@localhost lua-study]$ 
[dongsong@localhost lua-study]$ lua coroutine.lua 
co-body 1       10
foo     2
main    true    4
co-body r
main    true    11      -9
co-body x       y
main    true    10      end
main    false   cannot resume dead coroutine

2.skynet对协程的改造过程:说白了,把lua默认的coroutine.resume和coroutine.yield作为upvalue打进了DIY的lresume和lyield,并把协程启动时间和累计运行时间作为upvalue打进lstart/lstop/lresume/lyield

int  
luaopen_profile(lua_State *L) {  
        luaL_checkversion(L);  
        luaL_Reg l[] = {  
                { "start", lstart },  
                { "stop", lstop },  
                { "resume", lresume },  
                { "yield", lyield },  
                { NULL, NULL },  
        };  
        luaL_newlibtable(L,l);  
        lua_newtable(L);        // table thread->start time  
        lua_newtable(L);        // table thread->total time  
    /* 
 *  table -> total time 
 *  table -> start time 
 *  table -> libtable 
    */  
  
        lua_newtable(L);        // weak table  
        lua_pushliteral(L, "kv");  
        lua_setfield(L, -2, "__mode");  
    /* 
 *  table -> weak table 
 *  table -> total time 
 *  table -> start time 
 *  table -> libtable 
    */  
  
        lua_pushvalue(L, -1);  
        lua_setmetatable(L, -3);   
        lua_setmetatable(L, -3);  
    /* 
 *  table -> total time with weak metatable 
 *  table -> start time with weak metatable 
 *  table -> libtable 
    */  
  
        lua_pushnil(L);  
        luaL_setfuncs(L,l,3);  
    /* 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil  
    */  
  
        int libtable = lua_gettop(L); //libtable = 1  
  
        lua_getglobal(L, "coroutine"); //获取lua默认的coroutine库  
        lua_getfield(L, -1, "resume"); //获取lua默认的coroutine.resume函数  
  
        lua_CFunction co_resume = lua_tocfunction(L, -1); //co_resume=lua默认的coroutine.resume函数  
        if (co_resume == NULL)  
                return luaL_error(L, "Can't get coroutine.resume");  
        lua_pop(L,1); //把lua默认的coroutine.resume从stack中弹出去  
    /* 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil  
    */  
        lua_getfield(L, libtable, "resume");  
    /* 
 *  cfunction lresume 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil  
    */  
        lua_pushcfunction(L, co_resume);  
    /* 
 *  cfunction co_resume (lua default coroutine.resume) 
 *  cfunction lresume 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lresume/lyield: table->starttime, table->totaltime, nil  
    */  
        lua_setupvalue(L, -2, 3);  
    /* 
 *  cfunction lresume with upvalues: table->starttime, table->totaltime, co_resume (coroutine.resume) 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil  
 *           upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)  
    */  
        lua_pop(L,1);  
    /* 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil  
 *           upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)  
    */  
  
        lua_getfield(L, -1, "yield");  
  
        lua_CFunction co_yield = lua_tocfunction(L, -1); //co_yield=coroutine.yield  
        if (co_yield == NULL)  
                return luaL_error(L, "Can't get coroutine.yield");  
        lua_pop(L,1);  
    /* 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop/lyield: table->starttime, table->totaltime, nil  
 *           upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)  
    */  
        lua_getfield(L, libtable, "yield");  
        lua_pushcfunction(L, co_yield);  
        lua_setupvalue(L, -2, 3);  
    /* 
 *  cfunction lyield with upvalues: table->starttime, table->totaltime, co_yield (coroutine.yield) 
 *  coroutine (lua coroutine table) 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop: table->starttime, table->totaltime, nil  
 *           upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)  
 *           upvalues of lyield: table->starttime, table->totaltime, co_yield (coroutine.yield)  
    */  
  
        lua_settop(L, libtable);  
    /* 
 *  table -> libtable: {start=lstart, stop=lstop, resume=lresume, yield=lyield};  
 *           upvalues of lstart/lstop: table->starttime, table->totaltime, nil  
 *           upvalues of lresume: table->starttime, table->totaltime, co_resume (coroutine.resume)  
 *           upvalues of lyield: table->starttime, table->totaltime, co_yield (coroutine.yield)  
    */  
  
        return 1;  
}


你可能感兴趣的:(c,lua,Skynet)