Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Lua C Api, референс на значение, время жизни, сборщик мусора

Lua C Api, референс на значение, время жизни, сборщик мусора

Поделиться

Страницы: 1 2 Следующая

MrGobusПользовательwww5 ноя. 201715:19#0
Ковыряю C Api для Lua, возник такой вопрос:

Есть переменная userdata, хранит структуру в которую сохраняется указатель на себя для последующих  вызовов, двигаюсь в сторону системы событий (onClick, onRender и т.п.)

Указатель на self получаю вызовом luaL_ref(L, LUA_REGISTRYINDEX), дальше его как то использую, все работает, все хорошо, но вот неясно с освобождением. Грызя мануал я понял что luaL_ref  закрепляет переменную защищая ее от сборщика мусора. Что бы переменная стала доступной для сборки мусора ее надо luaL_unref(L, LUA_REGISTRYINDEX, data->self); который я вешаю на событие __gc, которое в свою очередь вызывается сборщиком мусора при удалении объекта. Соответственно переменная умирает после lua_close(), а collectgarbage() никак не влияет на жизнь переменной.

Вопрос а как, без метода :delete() решить проблему userdata так, чтобы иметь указатель на себя в Си структуре и не ликать память?

Правка: 5 ноя. 2017 15:20

andrekПостоялецwww5 ноя. 201716:54#1
light userdata?
MrGobusПользовательwww5 ноя. 201717:16#2
andrek
> light userdata
нет, вроде не то, это указатель безтиповый на Си данные
а надо наоборот - указатель на Lua переменную
ArochПостоялецwww5 ноя. 201719:37#3
MrGobus
> Вопрос а как, без метода :delete() решить проблему userdata так, чтобы иметь
> указатель на себя в Си структуре и не ликать память?
ты должен самостоятельно следить за инкрементом/декрементом счетчика.
WraithПостоялецwww6 ноя. 20171:21#4
MrGobus
> Вопрос а как, без метода :delete() решить проблему userdata так, чтобы иметь указатель на себя в Си структуре и не ликать память?
Не вполне понятно, что такое "метод :delete()", и как указатель в Си-структуре влияет на сборщик мусора в луе. Поясни.

>ты должен самостоятельно следить за инкрементом/декрементом счетчика.
Какой счетчик?

loysoПостоялецwww6 ноя. 20174:30#5
MrGobus
> luaL_unref(L, LUA_REGISTRYINDEX, data->self); который я вешаю на событие __gc
luaL_ref - это "создать сильную ссылку на объект Lua в Глобальном Environment - G". __gc на объект никогда не отработает, пока есть хоть одна сильная ссылка, "достижимая из G". Сильную ссылку уничтожают через luaL_unref. Проблема телеги и лошади у тебя, да.

Ты не написал - кто управляет временем жизни C++ объектов и Lua объектов. Если всем управляет GC - то это одно. Если C++ живет без GC и пытается держать сильные ссылки на Lua объекты - это другое. А если что-то типа LuaPlus - то это третье. И там пипец может возникнуть с циклическими ссылками (три объекта в цикле) через Lua-C++ boundary.

Приходится догадываться что у тебя в C++ что-то типа std::shared_ptr (или интрузивный Reference Counting).  Так?

В моем LuaCSP - Pull-модель (Lua тянет C++), вместо твоего Push (onClick, C++ стучится колбеками в Lua). И все C++ объекты управляются GC. Тогда если в C++ объекту А нужно запомнить ссылку на объект Б, то он делает lua ref. И lua unref, когда уничтожается по gc.

Как-то так:
https://github.com/loyso/LuaCSP/blob/cacee0bf8431331c462e8b2e78e6… annel.cpp#L65
RefInRegistry - это и есть luaL_ref
И тамже рядом - OpChannel::UnrefChannel (зануляет C++ ptr и C++-to-Lua ссылку)

Правка: 6 ноя. 2017 5:03

MrGobusПользовательwww6 ноя. 20178:43#6
Wraith

luaL_ref - блокирует переменную от сборки мусора. Разблокировать можно только в ручную (тот самый delete), это неудобно.

loyso

Да, телега и лошадь =)
У меня чистый Си, "но уши те же" =).
Я хотел организовать систему событий, на вроде onClick, onKey и т.п. где жизнью объекта управляет lua, но Си может обращаться к объектам самостоятельно.

Не вышло =) буду менять подход =)

loysoПостоялецwww6 ноя. 20179:00#7
MrGobus
> Я хотел организовать систему событий, на вроде onClick, onKey и т.п. где жизнью
> объекта управляет lua, но Си может обращаться к объектам самостоятельно.
Ну так можно же. Си "закрепляет" ссылку на Lua объект в ref/unref scope. GC тогда управляет жизнью Lua объекта после unref.

Если у тебя объект разрезан на си и lua часть, то:
В Lua 5.3 у каждой userdata появилось удобное uservalue. Тогда "универсальные ссылки" в userdata выглядят тупо дублем:
- Сишное identity объекта в userdata (raw или smart указатель на объект, к примеру)
- Ссылка на Lua таблицу (Lua часть объекта) в uservalue.
Это позволяет GC видеть твои Си ссылки, как edges GC-графа объектов.

Другой вариант (как у меня в LuaCSP): userdata представляет в Lua исключительно C++ объект. тогда uservalue может представлять просто произвольную ссылку-агрегат из этого C++ объекта на другой userdata/table объект. Я пока не переписал на Lua 5.3 :)

Правка: 6 ноя. 2017 9:06

loysoПостоялецwww6 ноя. 20179:09#8
MrGobus
> MrGobus
По моему опыту, "наследоваться в Lua от C/C++ объектов" и шарить this/self - не надо.
Надо четко - userdata - это C/C++ объект (со ссылками на другие Lua и C/C++ объекты внутри). table - это Lua объект (аналогично со ссылками на Lua/C/C++ объекты внутри).
Ну и независимые иерархии наследования или prototype-based цепочек делегирования.

Обращайся, если что :)

Правка: 6 ноя. 2017 9:11

MrGobusПользовательwww6 ноя. 20179:51#9
loyso
> Ну так можно же. Си "закрепляет" ссылку на Lua объект в ref/unref scope. GC
> тогда управляет жизнью Lua объекта после unref.

Все верно, но тогда становиться бессмысленным делать unref в "__gc", так как никогда не сработает =) Про это и разговор =)

>> Обращайся, если что :)

Ок спасибо.

loysoПостоялецwww6 ноя. 201710:58#10
MrGobus
> MrGobus
Си - а зачем так жестко? :) Очень интересно!
Почему не какое-нибудь подмножество C++ "за здравый смысл"?
MrGobusПользовательwww6 ноя. 201711:16#11
loyso
Не знаю, может быть. Я же выше говорил, что только начал ковырять Lua. Логика подсказывает что ресурсы нужно освободить при смерти объекта, в lua как такового диструктора нет но есть __gc =) Но вот не вышло =)

Если честно я сейчас пытаюсь собрать простенький vn движок (квест движок), ну и там хотелось бы как то так

player = Object.new("player")
player.loadTexture("image.png")
player.x = 100
player.y = 20
player.show()

say("hello world")
wait()

— но вот теперь придется 

player.delete()

вернее даже не так
от Object.new("player") придется и вовсе отказаться
сделать что-то вроде getPlayer("player") которая видимо вернет слабую юзердату ссылающуюся на структуру на стороне си и дальше lua будет через нее работать

а может вообще просто по имени обращаться, не особо быстро, но тут такое и не надо

но это уже так, черновики =)

MrGobusПользовательwww6 ноя. 201711:26#12
loyso
Ой туплю, почему Си а не Си++, да просто Си ненужен, слишком много гемора с классами и stl, в результате приходится все делать самому. Проще говоря нервы берегу.
loysoПостоялецwww6 ноя. 201711:28#13
MrGobus
> MrGobus
Ну пусть Lua менеджит все Си объекты, делов то. Не нужны ref/unref. Зови malloc в Player:new("player"), зови free в __gc.
А если какой-то подсистеме в си нужно вести список плееров, или боту нужна ссылка на плеера - то тогда ref/unref в соответствующих подсистемах.

Правка: 6 ноя. 2017 11:28

loysoПостоялецwww6 ноя. 201711:31#14
MrGobus
> много гемора с классами и stl
Оставь в своем С++ просто классы с одинарным public наследованием. А из stl типично надо немного - vector и map :)
Все легче будет.

Страницы: 1 2 Следующая

/ Форум / Программирование игр / Общее

2001—2017 © GameDev.ru — Разработка игр