2013-05-07 96 views
1

它的工作原理,如果一个C函数调用Lua函数当Lua调用C API 和LUA函数调用C API,longjmp的错误如何获得LUA脚本C功能

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 

回答

5

你叫由lua_newthread,不lua_newstate返回线程lua_resume。

因此,在你的代码,你要么必须改变第一lua_resumelua_(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_loadfileluaL_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_callklua_pcallklua_yieldk需要接收的延续函数作为参数。在你的情况下它是0.实际上,lua_yieldk可以取0作为延续函数,但是然后控制被传回到Lua脚本,在那里调用了C函数。
  • 接下来,对这些函数的任何调用都必须在协程线程中进行,而不是主线程。
  • 最后,你不能通过C调用边界。也就是说,当你调用lua_pcallk和pcallk正在调用yield的块时,继续功能被执行。但是,您不能让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,该函数刚刚生成。当收益发生时,执行跳转(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和堆栈状态,但仅仅演示了这些函数的机制。

+0

非常感谢你....我现在可以睡了^^ – user1790687 2013-05-08 05:25:18