相关 API

API 传入参数 返回值 说明

API

传入参数

返回值

说明

create(f)

函数,作为协程运行的主函数

返回创建的协程

如果还需要运行,需要使用resume操作

resume(co,[val1,…])

传入第一个参数是create函数返回的协程,剩下的参数是传递给协程运行的参数。

分两种情况,resume成功的情况下返回true以及上一次 yield函数传入的参数;失败情况下返回false,以及错误信息 第一次执行resume操作时,会从create传入的函数开始执行,之后会在该协程主函数调用yield的下一个操作开始执行,直到整个函数执行完毕。

第一次执行resume操作时,会从create传入的函数开始执行,之后会在该协程主函数调用yield的下一个操作开始执行,直到整个函数执行完毕。调用resume操作必须在主线程中。

runing


返回当前正在执行的协程,如果在主线程中被调用,将返回nil

status


返回当前协程的状态,有dead,running,suspend,

dead:死亡,runing:正常运行,suspend:挂起

wrap

与create类似,传入协程运行的主函数

返回创建的协程

wrap函数相当于结合了create和resume函数,所不同的是,wrap函数返回的是创建好的协程,下一次直接传入参数调用该协程即可,无需调用resume函数。

yield

变长参数,这些是返回,给此次resume函数的返回值。

返回下一个resume操作传入的参数值

挂起当前协程的运行,调用yield操作,必须在协程中。

测试函数

function foo (a)
    print("foo 函数输出", a)
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end
 
co = coroutine.create(function (a , b)
    print("第一次协同程序执行输出", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("第二次协同程序执行输出", r)
    local r, s = coroutine.yield(a + b, a - b)  -- a,b的值为第一次调用协同程序时传入
     
    print("第三次协同程序执行输出", r, s)
    return b, "结束协同程序"                   -- b的值为第二次调用协同程序时传入
end)
        
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")

上面测试案例 可以看到Lua中的 协程运行原理, 每次 resume,会从主函数里取 一个yield,并取得 yield的返回值。每次 取玩,yield就失效了,当没得取的时候, 协程就已经是死的了。

其中关键的就是,resume 和yield 之间的 数据交换。

从 from 协程中移动 n 个到 to 协程中。
创建协程在 函数 luaB_cocreate中。

在5.3中协程相关被集成到 lcorolib.c 里。
而在旧版本中 对应的脚本位置是在 lbaselib.c

lcorolib.c 5.3

static int luaB_cocreate (lua_State *L) {
  lua_State *NL;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  NL = lua_newthread(L);
  lua_pushvalue(L, 1);  /* move function to top */
  lua_xmove(L, NL, 1);  /* move function from L to NL */
  return 1;
}

它做的事情:

  • 检查类型,必须是一个函数对象。
  • 创建 lua_State 结构体
  • 移动函数到栈顶,
  • 将该函数从当前的lua_State移动到新创建的协程lua_State(NL)中。

lapi.c ,lua_xmove

LUA_API void lua_xmove (lua_State *from,lua_State *to,int n)
{
    int i; 
    if (from == to) return;
    lua_lock(to);
    api_checknelems(from,n);
    api_check(from,G(from)== G(to))	;
    api_check(from,to->ci->top - to-top >=n);
    from->top -=n;
    for(i =0;i<n;i++)
    {
        setobj2s(to,to->top++,from->top+i);
    }
    
    lua_unlock(to);
}

它主要就是实现了resume和yield函数的参数 两者之间的协程数据交换。

lua协程的执行流程

    • luaB_coresume 等待协程重新开始
    • lua_xmove 移动数据交换
    • lua_resume
    • luaV_execute
    • luaB_yield
    • lua_xmove
    • luaB_coresume