Lua C api: слишком много lua_states приводят к ошибкам? - PullRequest
2 голосов
/ 09 июля 2010

Мы работаем на нескольких компьютерах, выполняем программу, написанную на 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, следовательно, несколько состояний.

Сообщение об ошибке указывает на то, что он не может найти файл, который должен использовать ... который на самом деле там и снова, может использоваться без каких-либо проблем с меньшим количеством открытых состояний.

1 Ответ

2 голосов
/ 13 июля 2010

Фрагмент сайта вызова, который вы даете, не имеет смысла.У вас есть

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
}

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", и он будет искать модуль с именем "function" в обычным способом .Даже при вызове require() рекомендуется перехватить сообщение об ошибке и сообщить о нем.В этом случае, скорее всего, вам сообщат, что в длинном списке элементов, которые выглядело require, не было найдено ни одного модуля с именем "function".

Но ничего, что вы написали, на самом деле не вызывает функциюсам по себе.

Но здесь есть большая проблема.Не совсем понятно, зачем вам нужно более одного состояния Lua, особенно в однопоточной программе.Возможно ли, что [сопрограммы] [2] лучше подходят?

При наличии нескольких состояний вы должны помнить, что каждое состояние чрезвычайно изолировано от всех остальных.Единственный способ переместить значения из одного состояния в другое - использовать API C для извлечения значений из одного состояния и передачи их в другое.Сопрограммы дают некоторые преимущества отдельных состояний, в то же время разделяя общий набор глобалов.

...