Lua C api:太多lua_states导致错误?

时间:2010-07-09 12:18:46

标签: c api lua segmentation-fault

我们正在研究多台计算机,执行用c / c ++编写的程序并使用lua api,并且每一台计算机都会遇到不同的错误。它通常要么是一个分段错误,它的回溯导致我们调用bu liblua,或者通常在尝试调用nil值时给出,就像它是一个函数一样。

奇怪的是,它可以正常工作,直到我们达到许多状态(不,我们绝对需要多个状态,只有一个是不够的)。它们可能引用相同的文件-again,它可以正常工作,直到打开或不打开多个状态。

以下是他们如何打开,注册和关闭,以防在使用多个状态时出现问题:

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状态作为属性,因此有多个状态。

错误消息表明找不到它应该使用的文件......实际上是这样的,可以在没有任何问题的情况下使用,打开的状态更少。

1 个答案:

答案 0 :(得分:2)

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

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()返回的错误字符串可能会提供信息。有关更多信息,请在堆栈上放置合适的错误函数,并将其索引作为第4个参数传递给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
}

编辑2:在澄清之后,它仍然没有意义。

您的代码包含以下片段:

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状态,特别是在单线程程序中。 [coroutines] [2]有可能更合适吗?

对于多个州,您必须记住每个州与其他州完全隔离。将值从一个状态移动到另一个状态的唯一方法是使用C API从一个状态检索值并将它们推送到另一个状态。协同程序提供了单独状态的一些优点,同时共享一组通用的全局变量。