- 论坛徽章:
- 4
|
环境是lua5.2, 主要是把5.1->5.2的api change list过了一遍, 主要想验证coroutine的工作过程, 然后发现了两个坑, 大侠看看我理解的对不对, 多谢.
1, 写C模块命名为"mod", 写C宿主调用"mod", 其中"mod"模块只包含一个函数, 用于测试coroutine.- [root@vps616 study]# cat src/mod.c
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- static int run_twice(lua_State *L) {
- int ctx;
- if (lua_getctx(L, &ctx) == LUA_OK) {
- lua_pushstring(L, "hello");
- return lua_yieldk(L, 1, 2, run_twice);
- }
- lua_pushstring(L, " world");
- return 1;
- }
- static const luaL_Reg reg_api[] = {
- {"run_twice", run_twice},
- {NULL, NULL}
- };
- int luaopen_mod(lua_State *L) {
- lua_newtable(L);
- luaL_setfuncs(L, reg_api, 0);
- return 1;
- }
复制代码- [root@vps616 study]# cat src/main.c
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- int main(int argc, char* const argv[]) {
- lua_State *L = luaL_newstate();
- lua_State *LL = lua_newthread(L);
-
- lua_pushcfunction(L, luaopen_base);
- if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
- return 1;
- }
- lua_pushcfunction(L, luaopen_package);
- if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
- return 2;
- }
- lua_getglobal(L, "require");
- lua_pushstring(L, "mod");
- if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
- return 3;
- }
- lua_getfield(L, -1, "run_twice");
- lua_pushstring(LL, "1234");
- printf("top=%d\n", lua_gettop(LL));
- lua_xmove(L, LL, 1);
- printf("top=%d\n", lua_gettop(LL));
- if (lua_resume(LL, NULL, 0) == LUA_YIELD) {
- printf("yield=%s\n", lua_tostring(LL, -1));
- }
- printf("top=%d\n", lua_gettop(LL));
- if (lua_resume(LL, NULL, 0) == LUA_OK) {
- printf("return=%s\n", lua_tostring(LL, -1));
- }
- printf("top=%d %s\n", lua_gettop(LL), lua_tostring(LL, 1));
- return 0;
- }
复制代码 这个例子主要目的是观察run_twice在协程中执行的栈变化, 因为看lua.org/manual实在是描述的不太清晰.- [root@vps616 study]# bin/main
- top=1
- top=2
- yield=hello
- top=1
- return= world
- top=2 1234
复制代码 执行结果如下, 可见, yield=hello后top=1, 是yield的返回值, 而return= world之后top=2, 栈底是1234, 栈顶是 world.
我得到结论就是: 在协程未return消亡前, 协程的栈只会容纳resume与yield彼此交换的参数, 直到return才会重新将原本thread栈上的值暴露出来.
这一点和直接调用一个普通函数一样, 在函数内部(相当于thread未return)来看栈只容纳了参数, 其他参数与函数之前的内容暂时屏蔽掉了.
上面这个感悟是否和谐, 求指正.
再就是之前在5.1里被lua_yield坑过, 那个版本yield只能抛回给lua函数而不能抛回给c函数, 5.2有了k系列就不一样了, 但我看5.2手册里lua_yield的说明太朦胧:
int lua_yield (lua_State *L, int nresults);
This function is equivalent to lua_yieldk, but it has no continuation (see §4.7). Therefore, when the thread resumes, it returns to the function that called the function calling lua_yield.
我以为这句话的描述是lua_yield相当于lua_yieldk的function传入当前的function, 但实际上当再次resume的时候并没有重新调用发起lua_yield的那个函数, 而是当再次resume直接返回true, 栈也是空的, 我就是很郁闷了.
根据这个结论, 我认为lua_yield是在lua_pcallk/lua_callk的callee函数中调用的, 这样再次resume执行的是lua_pcallk/lua_callk指定的function。
这个结论是否和谐? |
|