Я люблю Lua. I love Lua.

Перехватчик для события удаления стейта.

Posted in Uncategorized by ilovelua on Февраль 11, 2014

Если Lua-библиотека, написанная на С, взаимодействует с несколькими Lua стейтами, то может потребоваться узнать о том, что какой-то из Lua стейтов удаляется. Сделать это можно так: при регистрации библиотеки в Lua стейте создаем безымянную userdata переменную, и у нее устанавливаем метатаблицу с методом __gc. Поскольку при удалении стейта у всех объектов вызываются финализаторы, то будет вызвана и эта функция безымянного объекта.

int onDestroyLuaState(lua_State* L)
{
	// делаем что-то полезное
	return 0;
}

const luaL_Reg libname[] = {
	// common functions
	{"Func1", func1},
	{"Func2", func2},
        ...
	{0, 0},
};

extern "C" __declspec(dllexport) int luaopen_libname(lua_State* L)
{
	lua_newuserdata(L, 0); // dummy for GC
	lua_createtable(L, 0, 1); // metatable
	lua_pushcfunction(L, onDestroyLuaState);
	lua_setfield(L, -2, "__gc");
	lua_setmetatable(L, -2);

	luaL_register(L, luaModuleName, libname);

	return 1;
}
Advertisements
Tagged with: ,

комментариев 6

Subscribe to comments with RSS.

  1. Алексей said, on Июль 22, 2014 at 2:06 пп

    Объект нужно сохранить иначе его удалит сборщик мусора. Например в реестре.

    • ilovelua said, on Июль 22, 2014 at 3:43 пп

      Объект все время находится на стеке Lua, поэтому сборщик мусора не помечает его как готовый к удалению.
      Приведенный ниже тест подтверждает это. Функция onDestroyLuaState() вызывается только во время вызова lua_close():


      lua_newuserdata(L, 0); // dummy for GC
      lua_createtable(L, 0, 1); // metatable
      lua_pushcfunction(L, onDestroyLuaState);
      lua_setfield(L, -2, «__gc»);
      lua_setmetatable(L, -2);

      lua_gc(L, LUA_GCCOLLECT, 0);
      lua_close(L);

      • Алексей said, on Июль 23, 2014 at 1:34 пп

        Этот пример не верный.
        В статье вы загружаете модуль.

        require «libname»
        Вызывает `luaopen_libname` который получает свой стек который очищается когда завершается вызов.

        корректный тест:


        local lib = require «libname»
        collectgarbage»collect»
        collectgarbage»collect»

  2. ilovelua said, on Июль 23, 2014 at 1:51 пп

    Э… Я вообще то на С++ пример показывал.
    lua_gc(L, LUA_GCCOLLECT, 0); делает тоже самое что и collectgarbage»collect».

    • Алексей said, on Июль 24, 2014 at 9:14 дп

      Это не имеет значения

      void test(){
      lua_State *L = luaL_newstate();

      lua_pushcfunction(L, luaopen_libname);
      lua_pcall(L, 0, 0, 0);

      // coll twice just in case
      lua_gc(L, LUA_GCCOLLECT, 0);
      lua_gc(L, LUA_GCCOLLECT, 0);

      lua_close(L);
      }

  3. ilovelua said, on Июль 24, 2014 at 11:35 дп

    Что ни делай (я проверял!), до тех пор, пока userdata лежит на стеке, сборщик мусора ее не удалит. В коде, который я привел, с этой переменной ничего не делается. А если ее сознательно или случайно вытолкнуть из стека, то да, сборщик мусора ее удалит.


Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: