当lua调用C API时,如果C函数调用lua函数,并且lua函数调用C API,longjmp错误
lua_yieldk,lua_callk和lua_pcallk它是如何工作的?
我的代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
lua代码
function t()
pause(2)
pause(2)
pause(2)
pause(2)
end
Run Code Online (Sandbox Code Playgroud)
你在一个返回的线程上调用lua_resume lua_newthread,而不是lua_newstate.
因此,在您的代码中,您必须将第一个更改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);
Run Code Online (Sandbox Code Playgroud)
或交换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
Run Code Online (Sandbox Code Playgroud)
我不关心在t这里设置全球的效率.
现在问题的要点:
lua_callk,lua_pcallk或者lua_yieldk需要接收的延续函数作为参数.在你的情况下,它是0.实际上,lua_yieldk可以将0作为延续函数,但然后控制被传递回Lua脚本,在那里发生对C函数的调用.lua_pcallkpcallk调用的块时,会执行continuation函数.但是,你不能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;
}
Run Code Online (Sandbox Code Playgroud)
Lua代码:
local pcallktest = ...
pcallktest()
Run Code Online (Sandbox Code Playgroud)
现在这段代码从文件"Test.lua"开始一个新的协同程序.Lua代码调用C函数pcallktest,后者又调用lua_pcallk另一个Lua函数,该函数只是产生.当产量发生时,执行跳转(longjmp)到cont函数,该函数作为参数提供lua_pcallk.当cont函数返回时,协程执行结束并lua_resume从_tmain返回开始.
一个例子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;
}
Run Code Online (Sandbox Code Playgroud)
Lua代码:
local yieldktest = ...
yieldktest()
Run Code Online (Sandbox Code Playgroud)
该位依次执行从C函数(yieldktest)中产生的协同程序.然后当协程恢复时(第二个lua_resume),控制权被传递回继续功能cont,该功能作为继续执行yieldktest.
这些示例不处理lua_getctx和堆栈状态,而只是演示这些函数的机制.