moo*_*cat 5 c lua multithreading coroutine luajit
我试图想出一个解决方案,从C函数中产生一个Luajit协程,它立即创建一个要在另一个OS线程上处理的tasklet.
根据Lua的各种文件,事情开始相互矛盾,这是不是完全有可能?文件不是很清楚,也没有解释推理.
Lua 5.1声明每个协程都有一个堆栈.但是,只有一个全局C堆栈.我不完全确定为什么这是一个障碍.
Lua 5.2显然用lua_pcallk和lua_yieldk修复了这个问题.但这些解释非常令人困惑.
但是这些都没有说明我正在使用的VM ......这是LuaJIT 2.0.4和LuaJIT 2.1.0.
谷歌搜索告诉我,Luajit 1.x已经实现了CoCo,显然每个lua线程(协同程序)都使用了真正的C堆栈.这允许从任何地方屈服.
只有一个搜索引导我看到显然LuaJIT 2.x没有实现coco,因为每个协程都使用C堆栈.
谁能告诉我从C产生协同程序的问题是什么?并验证我是否可以安全地从c产生/恢复luajit 2.x协同程序?
在参考Lua实现中,每个Lua协程都有自己的Lua堆栈,它只是内部的一个数组lua_State,与C堆栈无关。Lua 无法保存 C 堆栈(因为这在标准 C 中是不可能的),因此如果当前正在执行 C 函数,则无法生成协程。
例如,如果您有 Lua 函数a调用 C 函数b调用 Lua 函数c,并c尝试屈服,Lua 将无法保存局部变量b(因为它是 C 函数)并且会失败。
这也适用于很多内置的 Lua 函数。正如您提到的,在 Lua 5.1 中,实现不支持 yield across pcall,直到 Lua 5.2 显然添加了特殊函数以使其工作。
Coco 是标准 Lua 实现的补丁,它在协程中实现了单独的 C 堆栈,以便 Lua 现在可以“保存”C 函数变量。显然 LuaJit 1.x 也包含它。它不适用于 LuaJit 2.x,因为它是 Lua 的完全不同的实现。
LuaJit 2.x 在扩展页面中有以下段落:
完全可恢复虚拟机
LuaJIT VM 是完全可恢复的。这意味着您甚至可以跨上下文从协程中yield,而这对于标准Lua 5.1 VM 来说是不可能的:例如,您可以跨pcall() 和xpcall()、跨迭代器和跨元方法yield。
因此,显然跨内置函数的屈服应该可以工作,尽管它是否适用于任意 Lua C API 函数仍然是不明确的。然而测试起来很容易;编写一个简单的 C API 函数,该函数接受 Lua 函数并调用它,然后向其传递一个生成的函数。如果它不起作用,它应该抛出一个错误。
请注意,使用 FFI 加载的普通 C 函数根本不允许接触 Lua 状态。这包括试图屈服。