Собственно, почему не работает, стало немного понятно. Тут нужно работать со всей метатаблицей, т.к. её методы нуждаются в ссылке не конкретный экземпляр источника данных. Но, как это сделать, ещё не ясно. Можно ли функции "Close" как нибудь подсунуть "_DataSource" - "userdata" из таблицы?
dj.lexus написал: Собственно, почему не работает, стало немного понятно. Тут нужно работать со всей метатаблицей, т.к. её методы нуждаются в ссылке не конкретный экземпляр источника данных. Но, как это сделать, ещё не ясно. Можно ли функции "Close" как нибудь подсунуть "_DataSource" - "userdata" из таблицы?
Может, не мучиться, а написать этот фрагмент на lua и всунуть его вовнутрь вашей длл?
dj.lexus написал: Собственно, почему не работает, стало немного понятно. Тут нужно работать со всей метатаблицей, т.к. её методы нуждаются в ссылке не конкретный экземпляр источника данных. Но, как это сделать, ещё не ясно. Можно ли функции "Close" как нибудь подсунуть "_DataSource" - "userdata" из таблицы?
Может, не мучиться, а написать этот фрагмент на lua и всунуть его вовнутрь вашей длл?
Да, это тоже выход. А как кусок LUA кода вставить в DLL?
Да, я согласен, что во многих случаях можно обойтись возможностями LUA. Но, у меня задача - передавать данные в приложение на С. Поэтому, решено было оставить скрипт LUA пустым и все функции реализовать в DLL.
Я тоже передаю данные и туда и обратно, но это не мешает использовать и си функции и луа. Из опыта могу сказать что на Си надо делать то, что нет в луа например работу с различными форматами, потоками памятью.
Вячеслав + написал: Напишите, что Вы хотите выполнить на Lua - помогу перевести на С++.
Я пытаюсь сделать следующее:
Код
DS = CreateDataSource("SPBFUT", "RIM6", INTERVAL_M1); // Работает
...
C = DS:C(1); // Не получается
...
DS:Close(); // Не получается
Таблица DS содержит всё, как должно быть: C - function Close - function _DataSource - userdata T - function V - function SetUpdateCallback - function H - function SetEmptyCallback - function L - function O - function Size - function
int myfunction(lua_State* L) {
// DS = CreateDataSource("SPBFUT", "RIM6", INTERVAL_M1); // Работает
lua_getglobal(L, "CreateDataSource");
lua_pushstring(L, "SPBFUT");
lua_pushstring(L, "RIM6");
lua_getglobal(L, "INTERVAL_M1");
lua_call(L, 3, 1);
// результат на стеке
int DS = lua_gettop(L);
// C = DS:C(1); // Не получается
lua_getfield(L, DS, "C");
lua_pushvalue(L, DS);
lua_pushnumber(L, 1);
lua_call(L, 2, 1);
// результат на стеке
int C = lua_gettop(L);
// DS:Close(); // Не получается
lua_getfield(L, DS, "Close");
lua_pushvalue(L, DS);
lua_call(L, 1, 0);
// В Lua
// obj:func(param);
// это то же самое что
// obj.func(obj, param);
// как-то так
return 0;
}
int myfunction(lua_State * L) {
// DS = CreateDataSource ( "SPBFUT" , "RIM6" , INTERVAL_M1); // Работает
lua_getglobal(L, "CreateDataSource" );
lua_pushstring(L, "SPBFUT" );
lua_pushstring(L, "RIM6" );
lua_getglobal(L, "INTERVAL_M1" );
lua_call(L, 3 , 1 );
// результат на стеке
int DS = lua_gettop(L);
// C = DS:C( 1 ); // Не получается
lua_getfield(L, DS, "C" );
lua_pushvalue(L, DS);
lua_pushnumber(L, 1 );
lua_call(L, 2 , 1 );
// результат на стеке
int C = lua_gettop(L);
// DS: Close (); // Не получается
lua_getfield(L, DS, "Close" );
lua_pushvalue(L, DS);
lua_call(L, 1 , 0 );
// В Lua
// obj:func(param);
// это то же самое что
// obj.func (obj, param);
// как - то так
return 0 ;
}
Спасибо, заработало! Видимо, я не до конца понимаю организацию стека Lua. Правильно ли я понял, что таблица DS существует, пока указатель на неё хранится в стеке?
dj.lexus написал: Видимо, я не до конца понимаю организацию стека Lua.
Рекомендую к прочтению книгу "Roberto Ierusalimschy - Programming in Lua - 2013". В своё время потратил на неё неделю, и не жалею.
Цитата
dj.lexus написал: Правильно ли я понял, что таблица DS существует, пока указатель на неё хранится в стеке?
Немного подкорректирую Ваш вопрос:
Цитата
Правильно ли я понял, что значение DS существует, пока оно хранится в стеке?
Да. Это правильно.
Само значение, кроме того, можно скопировать (например, в качестве значения одного из ключей другой таблицы; lua_pushvalue как раз копирует значение). Таблицы на стеке хранятся в виде ссылок на содержимое таблиц, т.е. при таком копировании сами элементы таблицы не копируются - копируется только ссылка на таблицу.
За освобождение памяти выделенной под Lua-таблицы, userdata и строки отвечает сборщик мусора. Освобожение памяти обычно происходит позже удаления всех ссылкок на таблицу / userdata / string.
Кстати, а Вы уверены, что DS - это таблица? Что говорит
Код
message(type(DS),1);
?
Если DS - это таблица, то QLUA API в этом месте сделано немного кривовато, т. к. DS можно бы было сразу сделать userdata, чтобы Си код обработки методов DS выглядел лаконичней и чуть производительней.
Вячеслав + написал: Рекомендую к прочтению книгу "Roberto Ierusalimschy - Programming in Lua - 2013". В своё время потратил на неё неделю, и не жалею.
Спасибо за Ваш совет, книга лежит, ждёт прочтения.
Цитата
Вячеслав + написал: lua_pushvalue как раз копирует значение
Нашёл описание: void lua_pushvalue (lua_State *L, int index); Pushes a copy of the element at the given valid index onto the stack.
Получается, нужно знать индекс элемента, который требуется положить в стек. Как же сохранить ссылку на таблицу, чтобы она "не потерялась" до конца работы программы? Или не перепуталась со ссылкой на другой источник данных.
dj.lexus написал: Получается, нужно знать индекс элемента, который требуется положить в стек. Как же сохранить ссылку на таблицу, чтобы она "не потерялась" до конца работы программы? Или не перепуталась со ссылкой на другой источник данных.
Если между вызовами Си функций из Lua, то можно сохранить это значение в LUA_REGISTRYINDEX - это специальная таблица, видимая только из Си и хранящая важную информацию (удалять из неё что-то не своё точно не надо). См. API
Кстати, учтите, если Вы будете вызывать Ваши Си функции из разных потоков - поток main и поток callback'ов - то Вам нужно будет обеспечивать синхронный доступ к Вашим глобальным переменным. Можно с помощью std::mutex / std::recursive_mutex.
Вячеслав + написал: Если между вызовами Си функций из Lua, то можно сохранить это значение в LUA_REGISTRYINDEX - это специальная таблица, видимая только из Си и хранящая важную информацию (удалять из неё что-то не своё точно не надо). См. API idx = luaL_ref(L, LUA_REGISTRYINDEX) luaL_unref(L, LUA_REGISTRYINDEX, idx) lua_rawgeti(L, LUA_REGISTRYINDEX, idx)
Спасибо, эти функции у меня в коде есть. Меня насторожило то, что если сохранить ссылку
Код
idx = luaL_ref(L, LUA_REGISTRYINDEX) ,
потом вытолкнуть её из стека
Код
lua_pop(L, 1),
затем попытаться вернуть
Код
lua_rawgeti(L, LUA_REGISTRYINDEX, idx) ,
то Quik падает при выполнении таких операций.
Видимо, при удалении единственной ссылки на таблицу, Lua удаляет её содержимое.
Видимо, выходом в такой ситуации будет, как Вы писали:
Код
lua_setglobal(L, "myDS");
Правда, в этом случае, придётся склеивать индивидуальное символьное имя для каждого источника данных.
Про разные потоки callback'ов и main'a знаю, но про синхронизацию доступа пока не думал. Нужно будет это учесть.
Вячеслав + написал: Если между вызовами Си функций из Lua, то можно сохранить это значение в LUA_REGISTRYINDEX - это специальная таблица, видимая только из Си и хранящая важную информацию (удалять из неё что-то не своё точно не надо). См. API idx = luaL_ref(L, LUA_REGISTRYINDEX) luaL_unref(L, LUA_REGISTRYINDEX, idx) lua_rawgeti(L, LUA_REGISTRYINDEX, idx)
Спасибо, эти функции у меня в коде есть. Меня насторожило то, что если сохранить ссылку
Код
idx = luaL_ref(L, LUA_REGISTRYINDEX) ,
потом вытолкнуть её из стека
Код
lua_pop(L, 1 ),
затем попытаться вернуть
Код
lua_rawgeti(L, LUA_REGISTRYINDEX, idx) ,
то Quik падает при выполнении таких операций.
Видимо, при удалении единственной ссылки на таблицу, Lua удаляет её содержимое.
Видимо, выходом в такой ситуации будет, как Вы писали:
Код
lua_setglobal(L, "myDS" );
Правда, в этом случае, придётся склеивать индивидуальное символьное имя для каждого источника данных.
Про разные потоки callback'ов и main'a знаю, но про синхронизацию доступа пока не думал. Нужно будет это учесть.
А все callback'и выполняются в одном потоке?
Стек в луа - это просто область памяти, указатель на которую находится по адресу L->base При вталкивании в стек данные записываются по адресу, который записан в L->top Сначала там записан L->base, после каждого заталкивания L->top=L->top+1 При выталкивание происходит обратное действие. При этом происходит контроль границ стека и если адрес выходит за границы выдается сообщение луа. ------------------------------- Таким образом, КВИК падать не может из-за операций со стеком. ---------------------------- Если у Вас квик падает без сообщений, то ошибка в Вашем коде CИ, которай приводит к фатальной ошибке, которую никто не обрабатывает. Возможно Вы в своей программе куда-то не туда чего-то пишите. -------------------------------- Все колбеки выполняются в одном потоке. Но вот открытие источников надо делать в main. Не знаю для чего так сделано, но уж сделано.
Николай Камынин написал: Стек в луа - это просто область памяти, указатель на которую находится по адресу L->base При вталкивании в стек данные записываются по адресу, который записан в L->top Сначала там записан L->base, после каждого заталкивания L->top=L->top+1 При выталкивание происходит обратное действие. При этом происходит контроль границ стека и если адрес выходит за границы выдается сообщение луа. ------------------------------- Таким образом, КВИК падать не может из-за операций со стеком. ---------------------------- Если у Вас квик падает без сообщений, то ошибка в Вашем коде CИ, которай приводит к фатальной ошибке, которую никто не обрабатывает. Возможно Вы в своей программе куда-то не туда чего-то пишите. -------------------------------- Все колбеки выполняются в одном потоке. Но вот открытие источников надо делать в main. Не знаю для чего так сделано, но уж сделано.
Спасибо за разъяснения, проверю свой код. Да, ошибки не обрабатываю, нужно это добавить. Источник открываю в main, пока всё работает.
dj.lexus, Читайте внимательно документацию. У Вас сейчас есть всё для того (и книга и google), чтобы писать правильный код. Также отладочной печатью в контрольных точках можно понять, после какой операции "падает" программа, а с помощью отладочной печати значений lua_gettop(L) - что происходит со стеком Lua во время выполнения. Или наймите программиста / консультанта, который сделает это за Вас.