ПрограммированиеПодсказкиОбщее

Исправления Lua и luabind для корректной работы с lua-потоками

Автор:

При активной работе в Lua с lua-потоками в связке с luabind, иногда может возникнуть неприятная проблема, связанная с тем, что lua-поток будет удален раньше, чем luabind-объекты, которые были созданы во время исполнения данного потока. Так как luabind хранит ссылки на необходимые ему lua-объекты ввиде пары lua_State* и индекса в таблице ссылок, то после удаления потока, lua_State* становится недейсвительным, и при попытке удаления luabind-объекта будет происходить обращения по этой недействительной ссылке.

Простейший код, в котором воссоздается данная ошибка:

int _tmain(int argc, _TCHAR* argv[])
{
  lua_State* L = luaL_newstate();
  luabind::open(L);

  luabind::module(L)
  [
    luabind::class_<TestStruct>("TestStruct")
      .def_readwrite("x", &TestStruct::x)
      .def_readwrite("y", &TestStruct::y),
    luabind::def("func_get", &func_get),
    luabind::def("func_set", &func_set)
  ];

  lua_gc(L, LUA_GCSTOP, 0);

  lua_State* thread = lua_newthread(L);

  luaL_dostring(thread,
    "local val = func_get();\
    local tmp = val.x;\
    val.x = val.y;\
    val.y = tmp;\
    func_set(val);");

  lua_pop(L, 1);

  lua_gc(L, LUA_GCCOLLECT, 0);

  return 0;
}

Для того чтобы данной проблемы не возникало, необходимо внести некотрые исправления в исходный код Lua и luabind. Суть изменений — заставить сохранять luabind не ссылку на поток, в котором был создан объект, а ссылку на главный поток Luа, который не удаляется до окончания работы с Lua (более того, он всегда удаляется последним)

Исправления в Lua:

// ************************************************
// lua.h

LUA_API lua_State * (lua_mainstate) (lua_State *L);

// ************************************************
// lapi.cpp

LUA_API lua_State * lua_mainstate(lua_State *L)
{
  return G(L)->mainthread;
}

Исправления в luabind (luabind\detail\ref.hpp)

struct lua_reference
{

//........................... set - метод lua_reference

    void set(lua_State* L_)
    {
      reset();
      L = lua_globalstate(L_); // вот эту строку добавил и в следующей
      m_ref = ref(L_); // тут было m_ref = ref(L);
    }

При необходимости, можно внести аналогичные изменения в <luabind\handle.hpp>, который используется в luabind::object

#Lua, #потоки

2 февраля 2010 (Обновление: 11 апр 2010)

Комментарии [5]