【问题标题】:Lua C api : Too many lua_states lead to errors?Lua C api : 太多的 lua_states 会导致错误?
【发布时间】:2010-07-09 12:18:45
【问题描述】:

我们在多台计算机上工作,执行一个用 c/c++ 编码并使用 lua api 的程序,每台计算机都会因不同的错误而崩溃。这通常是分段错误,它的回溯导致我们调用了 bu liblua,或者在尝试调用 nil 值时通常给出的错误,就好像它是一个函数一样。

奇怪的是,在我们达到多个状态之前它工作得很好(不,我们绝对需要多个状态,只有一个是不够的)。它们可能会引用同一个文件 - 再次,它可以正常工作,直到打开的状态数少于 - 或不。

以下是它们的打开、注册和关闭方式,以防在使用多个状态时出现问题:

lua_State *state=lua_open();
luaL_openlibs(state)
luaL_loadfile(filename.c_str());
...
lua_register(state,"function",function); //dozens of them
...
lua_close(state);

在所有寄存器完成之前不会创建其他状态,是否关闭取决于使用状态的位置。

这是我在分段错误期间得到的:

#0  0x0013fe79 in ?? () from /usr/lib/liblua5.1.so.0
#1  0x0013325b in lua_pushlstring () from /usr/lib/liblua5.1.so.0
#2  0x001442ba in ?? () from /usr/lib/liblua5.1.so.0
#3  0x00144b61 in luaL_pushresult () from /usr/lib/liblua5.1.so.0
#4  0x00144de5 in luaL_gsub () from /usr/lib/liblua5.1.so.0
#5  0x0014fb52 in ?? () from /usr/lib/liblua5.1.so.0
#6  0x0014ffb7 in ?? () from /usr/lib/liblua5.1.so.0
#7  0x0013839a in ?? () from /usr/lib/liblua5.1.so.0
#8  0x00138834 in ?? () from /usr/lib/liblua5.1.so.0
#9  0x001337a5 in lua_call () from /usr/lib/liblua5.1.so.0
#10 0x0014f3ea in ?? () from /usr/lib/liblua5.1.so.0
#11 0x0013839a in ?? () from /usr/lib/liblua5.1.so.0
#12 0x00138834 in ?? () from /usr/lib/liblua5.1.so.0
#13 0x00133761 in ?? () from /usr/lib/liblua5.1.so.0
#14 0x00137ea3 in ?? () from /usr/lib/liblua5.1.so.0
#15 0x00137f05 in ?? () from /usr/lib/liblua5.1.so.0
#16 0x00133588 in lua_pcall () from /usr/lib/liblua5.1.so.0

以及相关代码:

lua_getglobal(L,"require");
lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0))
{
 ...

作为函数给出的字符串没有错,它在打开的状态数少于打开数的情况下工作正常。

当它输出“nil value”错误时,这意味着我们没有在程序内部使用相关的 lua_register 调用,但对于所有其他状态都是一样的,而且它们可以正常工作。

我认为这可能是由于一些内存泄漏,我真的不明白为什么,因为所有状态都已关闭。

这是否与 lua api 本身有关(比如可能一次打开预定数量的状态)?我知道我没有给出太多细节,但这实际上是几乎所有与lua相关的代码。

编辑:我忘记包含“require”语句(我调用它来推送模块),但它已经在代码中(因此,不是它不起作用的原因),对此感到抱歉。

程序是单线程的。一些对象有 lua 状态作为它们的属性,因此有多个状态。

错误消息表明它找不到它应该使用的文件...它实际上是存在的,并且可以在打开的状态较少的情况下毫无问题地使用。

【问题讨论】:

  • 确保使用 LUA_APICHECK 编译以在运行时捕获一些错误。如果您可以将您的代码简化为一个具有相同问题的小示例,请在此处发布完整代码,并可能还通过电子邮件发送 lua 列表。
  • 是否涉及多个线程或只有一个线程驱动多个状态?
  • 为了确保我们没有遗漏非常明显的内容,请注意不要在 关闭之后使用 Lua 状态,对吗?这样做将不可避免地涉及某种错误,但墨菲可以让事情几乎工作一段时间。

标签: c api lua segmentation-fault


【解决方案1】:

您提供的呼叫站点片段没有意义。你有

lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0)) 
{
 ...

其中不显示检索名为“function”的函数,而是调用堆栈顶部的任何内容,其第一个参数为字符串"function"

你是不是想说

lua_getglobal(L,"function");
if(!lua_pcall(L,0,0,0)) 
{
 ... // succcess
} else {
    // examine the error from the call for useful information
    fprintf(stderr, "lua_pcall: %s\n", lua_tostring(L,1));
}

编辑:lua_pcall() 返回的错误字符串可能提供信息。如需更多信息,请将合适的错误函数也放入堆栈,并将其索引作为第四个参数传递给lua_pcall。一个不错的选择是debug.traceback

void callback(lua_State *L, const char *fname) 
{
    int status
    lua_getglobal(L,"debug");       // put debug.traceback on the stack
    lua_getfield(L,-1,"traceback");
    lua_remove(L,-2);       
    lua_getglobal(L,fname);    // put function on the stack
    status = lua_pcall(L,0,0,-2)
    if (!status)        // call it with no parameters and no return values
    {
        // succcess
    } else {
        // examine the error from the call for useful information
        fprintf(stderr, "lua_pcall returned %d: %s\n", status, lua_tostring(L,1));
        lua_pop(L,1);               // remove error message from the stack
    }
    lua_pop(L,1);                   // remove debug.traceback from the stack
}

Edit2:经过您的澄清,仍然没有意义。

您的代码有以下片段:

lua_register(state,"function",function); //dozens of them
...

以后

lua_getglobal(L,"require");
lua_pushstring(L,"function");
if(!lua_pcall(L,1,0,0))
{
 ...

第一个片段创建一个全局变量,其值为每个 C 函数。如我的答案第一部分所述,您可以使用 get_global()lua_pcall() 调用这些函数。

第二个片段检索名为require 的全局变量,并使用字符串"function" 作为其唯一参数调用它。 Lua 中表示的等价物是require"function",它会在the usual way 中寻找一个名为“function”的模块。即使在调用require() 时,捕获并报告错误消息也是一个好主意。在这种情况下,很可能会告诉您在require 查找的一长串逐项列出的位置中没有一个名为“function”的模块。

但您编写的任何内容都没有真正调用函数本身。

但这里有一个更大的问题。不完全清楚为什么首先需要多个 Lua 状态,尤其是在单线程程序中。 [协程][2] 是否可能更合适?

对于多个状态,您必须记住,每个状态都与其他所有状态极为隔离。将值从一种状态移动到另一种状态的唯一方法是使用 C API 从一种状态检索值并将它们推送到另一种状态。协程具有独立状态的一些优点,同时共享一组通用的全局变量。

【讨论】:

  • 忘记写之前推送的“require”语句,因为代码在另一台计算机上,抱歉不清楚。
猜你喜欢
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 2017-08-01
  • 2012-11-25
  • 2019-04-18
  • 1970-01-01
相关资源
最近更新 更多