如何在C函数中生成lua脚本

时间:2013-05-07 10:25:57

标签: lua yield mscapi

当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;
}

lua代码

function t()
pause(2)
pause(2)
pause(2)
pause(2)
end

1 个答案:

答案 0 :(得分:6)

您在lua_newthread返回的主题上调用lua_resume,而不是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);

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_callklua_pcallklua_yieldk都需要接收继续函数作为参数。在你的情况下,它是0.实际上,lua_yieldk可以取0作为延续函数,但然后控制被传递回Lua脚本,在那里发生了对C函数的调用。
  • 接下来,必须在协程线程内进行对这些函数的任何调用,而不是主线程。
  • 最后,你无法跨越C呼叫边界。也就是说,当您调用lua_pcallk并且pcallk正在调用yield的块时,将执行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;
}

Lua代码:

local pcallktest = ...
pcallktest()

现在这段代码从文件“Test.lua”开始一个新的协同程序。 Lua代码调用C函数pcallktest,后者又调用另一个Lua函数上的lua_pcallk。当产量发生时,执行跳转(longjmp)到cont函数,该函数作为lua_pcallk的参数提供。当cont函数返回时,协程执行结束,lua_resume的{​​{1}}返回。

_tmain的一个例子:

lua_yieldk

Lua代码:

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;
}

该位依次执行从C函数(local yieldktest = ... yieldktest() )内产生的协同程序。当协程恢复后(第二个yieldktest),控制权将传递回继续函数lua_resume,该函数作为cont的延续执行。

这些示例不涉及yieldktest和堆栈状态,而只是演示这些函数的机制。