相关 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