Видимо здесь речь идет о вложенных вызовах - например из Lua-функции вызывают C-функцию. В этом случае для C-функции стек не будет содержать аргументов вызывающей lua-функции. Если планируется использовать с-функцию, которая каким-то образом манипулирует Lua стеком, из разных потоков операционной системы, то необходимо либо синхронизровать доступ к lua_State, либо завести новый "поток" с помощью lua_newthread()
Let_it_go написал: У меня в dll две функции. Обе постоянно что то делают со стеком. Есть ли риски того, что они будут по ошибке брать элементы друг друга? Или для каждой из них свой стек и путаница не грозит?
В такой ситуации Вам нужно создать два разных стека в каждом потоке с помощью lua_newthread()
Проверка индекса поможет только если он выходит за пределы массива хранилища. Если сделок уже стало больше, то получите новую сделку по указанному индексу. Но вообще получение nil в результате это повод прекратить текущую обработку и начать все заново.
Добрый день. getItem вернет nil если таблица указана некорректно, либо если нет элемента с таким индексом. Если возвращается nil, то попробуйте сравнить индекс элемента с результатом getNumberOf(), возможно таблица очистилась пока вы перебирали результаты.
Добрый день. у Вас ошибка в коде. Вместо bit.band(stop_order.flags,0x400)==0x1 надо проверять bit.band(stop_order.flags,0x400) ~= 0 Результат битового AND нужно сравнивать не с единицей, а на неравенство с нулем.
Добрый день. Считаем что 1.dll и 2.dll лежать в одном каталоге в 1.dll должен присутствовать код, который делает примерно следующее (без обработки ошибок): 1.
Код
bool getDllPath(char *out_path, size_t max_size)
{
char path[MAX_PATH] = {};
HMODULE hm = NULL;
if( GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPSTR) &getDllPath, &hm ) )
{
GetModuleFileName( hm, path, sizeof(path) );
/*
тут надо обрезать из path "1.dll" или "\\1.dll", по вкусу
и скопировать в out_path
*/
.....
return true;
}
return false;
}
2. При успешном выполнении к out_path приклеить "2.dll" и загрузить ее через LoadLibrary
Добрый день. Следует понимать, что такая функция будет доступна только скриптам. Возможно пересечение идентификаторов со скриптами которые такую функцию не используют, скриптами QPILE и внешними транзакциями. Ну и рестарт терминала приведет к сбросу счетчика.
Suntor написал: Что же касается связки luac + bin2c, то она не сработает в качестве защиты. Там нет компиляции кода. Там просто упаковка luac кода в секцию данных и с последующим вызовом по указателю.
luac на выходе даст вам как раз байт-код. Например файл hello.lua содержащий строку print "hello" bin2c представит в виде :
Код
/* code automatically generated by bin2c -- DO NOT EDIT */
{
/* #include'ing this file in a C program is equivalent to calling
if (luaL_loadfile(L,"hello.lua")==0) lua_call(L, 0, 0);
*/
/* hello.lua */
static const unsigned char B1[]={
112,114,105,110,116, 32, 34,104,101,108,108,111, 34,
};
if (luaL_loadbuffer(L,(const char*)B1,sizeof(B1),"hello.lua")==0) lua_call(L, 0, 0);
}
Добрый день. Видимо имелась ввиду связка luac + bin2c Сначала скрипт компилируется, затем полученный файл конвертируется с помощью bin2c или аналогичной и встраивается в код dll Пример можно посмотреть тут: http://lua-users.org/wiki/BinToCee
Если не трудно, то все же скажите, как, и как именно "блокируются" потоки в table.sconcat() - это все хочется знать, чтобы понимать, как именно лучше писать Lua код, какая операция сколько стоит...
в оригинальной версии table.concat, насколько я помню, блокировка происходит в момент получения элемента таблицы. В sconcat блокировка происходит на время выполнения всего цикла.
Цитата
Теперь, например, стало ясно, что в начале скрипта нужно писать
Код
local string, table, pairs, ipairs = string, table, pairs, ipairs
и т.д., чтобы не лочить global environment при каждом доступе к string.something() и т.д.
Это делается для ускорения обращения к нужным данным и не связано с блокировками.
1: приводит ли присвоение nil глобальным переменным из функции main() (то есть не главного потока) к неопределенным ситуациям?
Смотря как написан код
Код
t={}
...
function main()
...
t=nil
...
end
OnSmth()
t.x = 1
t.y = 2
t.z = 3 -- тут может возникнуть ошибка attempt to index global 't' (a nil value)
Цитата
2: имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая critical section )? Или же вообще все потоки волшебным образом останавливаются, ну, так, "на всякий случай"? :)
Другой "поток" волшебным образом останавливается, если будет обращение к глобальным данным.
Цитата
3: как вообще тогда использовать table.ssort() ?
в описанной Вами ситуации - никак.
Цитата
Думаем про table.sinsert() и table.sremove(): 4: в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри ipairs(), t[key], или еще где)? Что именно сделано, чтобы все не "взорвалось"? Или "так делать нельзя"?
Как и в любых других языках программирования - изменение содержимого контейнера в одном потоке и итерация по элементам в другом может привести к неопределенной ситуации. Данные останутся консистентны, но итераторы (pairs, ipairs) могут работать не так как Вы ожидаете.
Цитата
5: а какие "сообщения" можно посылать таким образом? Абсолютно любые "типы" Lua, или есть ограничения? Этот вопрос связан со следующим:
Не совсем понятно, поясните.
Цитата
6: а как потоки дружат со сборщиком мусора ( garbage collector )? Он один на все потоки, или по одному на каждый? Если один, то в каком потоке выполняется, и что именно сделано, чтобы GC в одном потоке не "взорвал" другой работающий поток, и не "взорвался" сам, считая свободной память, которую другой поток как раз начинает использовать)? Если же GC у каждого потока свой, то в случае message passing как в примере выше как именно передается ownership (то есть чей GC отвечает за рекламацию сообщения)?
Сборщик мусора один. Вообще потоки не являются потоками в "классическом" понимании. Это скорее новый объект с отдельным стеком для вызовов функций и локальных переменных. При этом у них общие глобальные данные. Попытка обращения к ним из одного "потока" блокирует другой, если он тоже обращается к ним.
Добрый день. Эксперимернты показали, что взаимных блокировок (deadlock) при работе скрипта не происходит. Просто основной поток фронта очень загружен и не откликается на действия пользователей. Потокобезопаные функции библиотеки table устроены так, что на время выполнения полностью блокируют все остальные потоки для данной виртуальной машины Lua. Учитывая что таблица events в Вашем примере постоянно растет, то и время работы функций sinsert и ssort все время увеличивается.
Добрый день. Если не найдена бумага в классе, либо если есть открытые стаканы. Возможен вариант когда число Subscribe_Level_II_Quotes было больше чем Unsubscribe_Level_II_Quotes. Этот счетчик глобальный, на уровне терминала
Добрый день. ошибки, которые может вернуть CreateDataSource: - "invalid context" - функция вызвана вне main или других зарезервированных функций; - "unknown class code"; - "unknown param name" - не найден такой параметр на заданном классе; - "static param" - параметр в ТТП есть, но он берется из описания бумаги (getSecurityInfo); - "CreateNetDataSource failed" - это ошибка общего характера, например не хватило памяти.
Andrei2016 написал: 9) Допустим, программно выставлены 2 заявки: одна с trans_id = 102 в 14-15мск, другая с trans_id = 107 в 14-25мск. Обе заявки зарегистрированы биржей, обе активны. Далее происходит отправка двух транзакций вида "KILL_ORDER": сначала отправлена заявка на снятие активного ордера с trans_id = 102 и сразу же - следующей командой sendTransaction() - на снятие ордера с trans_id = 107. Вопрос: возможна ли ситуация, что вначале будет снят ордер с trans_id = 107 и лишь затем снимется ордер с trans_id = 102? Или же порядок вызова OnOrder() будет жестко совпадать с порядком транзакций на снятие ордеров: т.е. сначала в любом случае придет вызов OnOrder() с trans_id = 102 и лишь после него OnOrder() с trans_id = 107? Вопрос весьма существенный, поэтому прошу прокомментировать максимально точно.
Добрый день. Очень часто шлюзы используют несколько транзакционных коннектов к торговой системе. Сервер отправляет транзакцию в первый найденный свободный коннект. Поэтому теоретически может возникнуть ситуация, когда, в Вашем примере, транзакция с trans_id=107 выполнится раньше чем 102 со всеми вытекающими отсюда результатами.
Andrei2016 написал: Можно ли уверенно сказать, что при любом подобном - "удельном" - изменении состояния заявки функция OnOrder() будет вызвана НЕ БОЛЕЕ ДВУХ раз? Если это не так, то прошу указать, какое максимальное количество вызовов OnOrder(), относящихся к одному конкретному изменению состояния заявки может произойти.
Вот возможный сценарий заявки, на каждый пункт будет OnOrder: 1. поставили заявку на 100 лотов; 2. исполнилась сделка на 1 лот; 3. исполнилась сделка на 1 лот; ... 100. исполнилась сделка на 1 лот; 101. сняли оставшийся лот; Если сервер решит что необходимо что-то дописать или поменять в заявке, то в любом пункте возможен дополнительный вызов OnOrder.
Цитата
7) Может ли вызов OnTrade() придти раньше вызова OnOrder() по одной и той же заявке? Прошу прокомментировать случаи:
Теоретически может. Самое простое что может прийти в голову - торговая система предоставляет "опросный" интерфейс для получения данных. В этом случае может наступить момент, когда клиент отправил транзакцию, она зарегистрирована в ТС и заявка тут же сыграла, но шлюз в этот момент запрашивал новые сделки. Тогда сначала приедет сделка по заявке, а потом сама заявка. Общая рекомендация для сделок и заявок - не "затачивать" алгоритм на определенный порядок вызова OnOrder/OnTrade и их количество
Цитата
возможна ли в штатном режиме работы ситуация, когда ответный вызов OnTransReply() на отправленную программным образом заявку не поступит вовсе? Если да, то прошу пояснить в каких конкретно случаях такое возможно.
Такая ситуация говорит о том, что что-то пошло не так. Перерублен кабель сразу после отправки транзакции, упал сервер QUIK, апала торговая система и т.п.
Ситуация, которую я описал выше значит что шлюз подключен к серверу и торговой системе. Изменится ли значение параметра и станет отличным от 0 мы не знаем.
Это значит, что сервер что-то получил от шлюза, подключенного к соответствующей площадке. Если торговая система изменит этот параметр, то он изменится и на сервере.
Добрый день. Можно смотреть на param_image. Если param_value = 0 и param_image ~= "", то это значит что действительно получено значение 0 от соответствующего шлюза.
Добрый день. https://habrahabr.ru/post/112953/ - тут можно почитать про вычисления с плавающей точкой. Если хотите сравнить полученные значения в разных языках, то выводите их на печать с одинаковой точностью. в Lua, например, так:
Добрый день. Пришлите нам пример кода для тестов. Кроме того, если вставлять и удалять элементы с индексом 1, то мы получим линейную зависимость времени работы от размера таблицы.
Единственное надежное решение - запретить загрузку сторонних dll в терминал. В противном случае никакая архитектура не спасает. В Вашем случае есть два решения - перенесите всю работу с трубой в main(), либо синхронизируйте доступ к ней из разных потоков.
Добрый день Исследования показали, что причиной зависания является скрипт на Lua qapi.lua. В функции main() в цикле происходит чтение/запись в named pipe. При потере соединения вызывается вот такой код:
Код
function OnClose()
if mode == 1 then
r = ffi.C.ReadFile(handle, readBuffer, 4*1024, bytesRead, nil);
end
mode = 0
disconnectAndReconnect(false)
end
function OnDisconnected()
OnClose()
end
function disconnectAndReconnect(doConnect)
ffi.C.FlushFileBuffers(handle)
ffi.C.DisconnectNamedPipe(handle)
if doConnect then
assert(ffi.C.ConnectNamedPipe(handle, poverlapped), "Соединение установить не удалось")
end
end
В зависимости от состояния main() зависание происходит либо тут: kernel32.ReadFileImplementation -> KERNELBASE.ReadFile - > ntdll.ZwWaitForSingleObject либо тут: KERNELBASE.FlushFileBuffers -> ntdll.ZwFlushBuffersFile Функция OnDisconnected выполняется в основном потоке терминала, и зависание в ней приводит к зависанию GUI. Рекомендуем синхронизировать доступ к named pipe из разных потоков.
Добрый день. Задача в общем случае не решаема. Вот простой пример:
Код
function find_var(value)
for k, v in pairs(_G) do
if v == value then
print('for ' .. value .. ' found ' .. k)
end
end
end
x='qwerty'
find_var('qwerty')
print '-------'
y=x
find_var('qwerty')
--[[
output:
for qwerty found x
-------
for qwerty found y
for qwerty found x
--]]
Реально в памяти будет лежать одна копия строки 'qwerty', но ссылка на нее в двух разных переменных. Аналогично с таблицами и функциями. Однозначно по значению нельзя найти имя переменной.