Lua C API:太多的lua_states导致错误?

我们正在多台计算机上工作,执行用c / c++编码并使用lua api的程序,它们每一个都会因不同的错误而崩溃。通常这要么是一个分段错误,其回溯将我们带回到由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值”错误时,它意味着我们没有从程序内部使用相关的lua_register调用,但对于所有其他状态都是相同的,而且它们都没有任何问题。

我认为这可能是由于某些内存泄漏引起的,但我真的不知道为什么,因为所有状态都已关闭。

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

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

该程序是单线程的。某些对象的属性具有lua状态,因此有多个状态。

错误消息表明它找不到应该使用的文件...实际上它存在,而且再次打开少量状态时可以使用,没有任何问题。

原文链接 https://stackoverflow.com/questions/3212475

点赞
stackoverflow用户68204
stackoverflow用户68204

你提供的调用代码片段没有意义。你有:

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

这并没有显示检索名为“function”的函数,而是用字符串“function”作为其第一个参数,调用了栈顶的任何内容。

也许你的意思是:

lua_getglobal(L,"function");
if(!lua_pcall(L,0,0,0))
{
 ... // 成功
} else {
    // 检查有用信息的调用错误
    fprintf(stderr, "lua_pcall: %s\n", lua_tostring(L,1));
}

编辑:lua_pcall()返回的错误字符串可能提供有用信息。想要更多信息,可以将适当的错误函数放在堆栈上,并将其索引作为第四个参数传递给lua_pcalldebug.traceback是一个不错的选择。

void callback(lua_State *L, const char *fname)
{
    int status
    lua_getglobal(L,"debug");       // 将debug.traceback放在堆栈上
    lua_getfield(L,-1,"traceback");
    lua_remove(L,-2);
    lua_getglobal(L,fname);    // 将函数放在堆栈上
    status = lua_pcall(L,0,0,-2)
    if (!status)        // 调用并没有参数或返回值
    {
        // 成功
    } else {
        // 检查有用信息的调用错误
        fprintf(stderr, "lua_pcall returned %d: %s\n", status, lua_tostring(L,1));
        lua_pop(L,1);               // 从堆栈中删除错误消息
    }
    lua_pop(L,1);                   // 从堆栈中删除debug.traceback
}

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

你的代码有以下片段:

lua_register(state,"function",function); //几十个
...

稍后有:

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",它将查找一个名为“function”的模块,在通常的方式中。即使调用require(),检查并报告错误消息也是一个好主意。在这种情况下,它可能会告诉您require查找的长列表中没有名为“function”的模块。

但是,你的代码中并没有真正调用函数本身。

但是这里有一个更大的问题。不清楚为什么你需要多个Lua状态,特别是在单线程的程序中。可能使用协程更合适吗?

在使用多个状态的情况下,必须记住每个状态与其他所有状态之间的极度隔离。将值从一个状态移动到另一个状态的唯一方法是使用C API从一个状态检索值并将其推入另一个状态。协程有一些独立状态的优点,同时共享一组公共全局变量。

2010-07-12 21:04:59