lua 调用 C API 时有效 如果一个C函数调用lua函数,lua函数调用C API,longjmp错误
lua_yieldk、lua_callk 和 lua_pcallk 它是如何工作的?
我的 C 代码:
int trace(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
printf("%d:%s\n", GetTickCount(), str);
return 1;
}
int pause(lua_State *L)
{
printf("pause");
return lua_yield(L, 0);
}
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction( L, pause );
lua_setglobal( L, "pause" );
lua_pushcfunction( L, trace );
lua_setglobal( L, "trace" );
if (luaL_loadfile(L, "test.lua"))
error(L, "cannot run script %s\n", lua_tostring(L,-1));
lua_resume(L, NULL, 0);
lua_getglobal(L, "t");
lua_pcallk(L, 0, 0, 0, 0, 0);
lua_resume(L, NULL, 0);
lua_resume(L, NULL, 0);
lua_resume(L, NULL, 0);
lua_resume(L, NULL, 0);
lua_close(L);
getchar();
return 0;
}
lua代码
function t()
pause(2)
pause(2)
pause(2)
pause(2)
end
最佳答案
您在 lua_newthread
而不是 lua_newstate
返回的线程上调用 lua_resume。
因此在您的代码中,您要么必须将第一个 lua_resume
更改为 lua_(p)call
:
if (luaL_loadfile(L, "test.lua"))
error(L, "cannot run script %s\n", lua_tostring(L,-1));
lua_pcall(L, 0, 0, 0);
或者将 luaL_loadfile
换成 luaL_dofile
:
if (luaL_dofile(L, "test.lua"))
error(L, "cannot run script %s\n", lua_tostring(L,-1));
//lua_resume(L, NULL, 0); Not necessary anymore
我在这里与设置全局 t
的效率无关。
现在进入问题的重点:
- 首先,每次调用
lua_callk
、lua_pcallk
或lua_yieldk
都需要接收一个延续函数作为参数。在你的情况下它是 0。实际上,lua_yieldk
可以将 0 作为延续函数,但随后控制权将传递回 Lua 脚本,在该脚本中调用 C 函数。 - 接下来,对这些函数的任何调用都必须在协程线程中进行,而不是在主线程中进行。
- 最后,您不能跨越 C 调用边界让步。也就是说,当您调用
lua_pcallk
并且 pcallk 正在调用的 block 产生时,将执行延续函数。但是,您不能让lua_pcallk
调用一个 Lua 函数,而该函数又调用一个产生的 C 函数(在您的示例中为pause
)。这是被禁止的。
一个lua_pcallk
的例子:
int cont(lua_State *L)
{
getchar();
return 0;
}
int pcallktest(lua_State *L)
{
luaL_loadstring(L, "yield()");
int test = lua_pcallk(L, 0, 0, 0, 0, cont);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_State *T = lua_newthread(L);
luaL_loadfile(T, "Test.lua");
lua_pushcfunction(T, pcallktest);
lua_resume(T, NULL, 1);
return 0;
}
Lua代码:
local pcallktest = ...
pcallktest()
现在这段代码从文件“Test.lua”开始一个新的协程。 Lua 代码调用 C 函数 pcallktest
,后者又在另一个 Lua 函数上调用 lua_pcallk
,该函数仅产生。当 yield 发生时,执行跳转 (longjmp) 到 cont
函数,该函数作为参数提供给 lua_pcallk
。当 cont
函数返回时,协程执行结束,_tmain
中的 lua_resume
返回。
一个lua_yieldk
的例子:
int cont(lua_State *L)
{
getchar();
return 0;
}
int yieldktest(lua_State *L)
{
return lua_yieldk(L, 0, 0, cont);
}
int _tmain(int argc, _TCHAR* argv[])
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_State *T = lua_newthread(L);
luaL_loadfile(T, "Test.lua");
lua_pushcfunction(T, yieldktest);
lua_resume(T, NULL, 1);
lua_resume(T, NULL, 0);
return 0;
}
Lua代码:
local yieldktest = ...
yieldktest()
此位依次执行从 C 函数 (yieldktest
) 中产生的协程。当协程随后恢复时(第二个 lua_resume
),控制被传递回延续函数 cont
,它作为 yieldktest
的延续执行.
这些示例不处理 lua_getctx
和堆栈状态,而只是演示这些函数的机制。
关于lua - 如何在 C 函数中生成 lua 脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16416711/