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

标签 lua yield mscapi

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_callklua_pcallklua_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/

相关文章:

function - lua函数包括表中的参数

lua - 如何在此处增加 `k`?

javascript - yield [] 和 yield all() 的区别 - ES6/redux-saga

python - Asyncio 在多个 future 到达时生成结果

OpenSSL 和 MS CryptoAPI : different digital signatures

node.js - NodeJS 中的 TLS 连接使用证书存储中的证书和 key

c# - LuaInterface - 在 .Net 3.5/.Net 4.0 下编译 FileLoadException

lua - 始终在最上面的窗口并保持焦点,在 AwesomeWM 上

c# - C# : are they faster than iterators, 中的纤程,有人使用过它们吗?

C# 使用 certenroll.dll 在没有 CA 的情况下生成非自签名客户端 CX509Certificate 请求