kroki (Автор тем)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
OnTransReply status, Какие статусы нетерминальные?
 
Документация:
Цитата
Статус транзакции. Возможные значения:
«0» – транзакция отправлена серверу;
«1» – транзакция получена на сервер QUIK от клиента;
«2» – ошибка при передаче транзакции в торговую систему. Так как отсутствует подключение шлюза Московской Биржи, повторно транзакция не отправляется;
«3» – транзакция выполнена;
«4» – транзакция не выполнена торговой системой. Более подробное описание ошибки отражается в поле «Сообщение»;
«5» – транзакция не прошла проверку сервера QUIK по каким-либо критериям. Например, проверку на наличие прав у пользователя на отправку транзакции данного типа;
«6» – транзакция не прошла проверку лимитов сервера QUIK;
«10» – транзакция не поддерживается торговой системой;
«11» – транзакция не прошла проверку правильности электронной цифровой подписи;
«12» – не удалось дождаться ответа на транзакцию, т.к. истек таймаут ожидания. Может возникнуть при подаче транзакций из QPILE;
«13» – транзакция отвергнута, так как ее выполнение могло привести к кросс-сделке (т.е. сделке с тем же самым клиентским счетом);
«14» – транзакция не прошла контроль дополнительных ограничений;
«15» – транзакция принята после нарушения дополнительных ограничений;
«16» – транзакция отменена пользователем в ходе проверки дополнительных ограничений

Я правильно понимаю, что «0», «1» и «15» являются нетерминальными статусами, то есть после их получения будет еще вызов OnTransReply() с другим статусом - так?  Остальные все терминальные; все, кроме «3» - ошибка (плюс «12» в QLua не бывает).  Все верно?

Если не трудно, плиз опишите, когда возникают «0», «1» и «15» (в моей версии Quik «0» и «1» не замечал, ограничения для «15» видимо не задавал).
Каков реальный сценарий вызова OnDepoLimitDelete(), OnMoneyLimitDelete(), OnFuturesLimitDelete()?
 
В каких реальных случаях вызываются OnDepoLimitDelete(), OnMoneyLimitDelete(), OnFuturesLimitDelete() (первые два для limit_kind >= 0, внутренние не особо интересны)?  Кто-нибудь встречал эти вызовы в реале?

Кстати, а зачем вызываются ползовательские callbacks с limit_kind < 0?  Какие осмысленные действия он бы мог сделать (хотя бы в теории)?
Гарантируется ли упорядоченность результата getQuoteLevel2()?
 
Сейчас в выдаче getQuoteLevel2() массивы bid и offer упорядочены по цене, но в документации это не упомянуто.  Гарантируется ли такая упорядоченность, или опираться на это нельзя?  Заранее спасибо за ответ!
Интерактивная работа с QLua
 
Написал себе скрипт для интерактивной работы с QLua, возможно пригодится кому-то еще (иногда бывает нужно что-то быстро попробовать не строча полноценный скрипт).  Код лежит на GitHub (хотел разместить прямо здесь, но (по крайней мене при нажатии кнопки "Просмотр") в случайных местах кода появлялись символы пробела - не понял, почему).

Для использования запускаем Quik из командной строки.  То есть открываем окошко для ввода команд, пишем:
Код
C:\Windows\system32> chdir \Path\to\Quik\dir
C:\Path\to\Quik\dir> info.exe
Далее из Quik запускаем qlua-console.lua, в терминале появляется приглашение для ввода.  Можно исполнять любой код Lua, вызывать функции QLua и определять callbacks.  Дополнительно доступна функция qluaDump(...) - возвращает строковое представление переданных аргументов.  Например:
Код
qlua> 2 + 3
5
qlua> getClassesList()
'CROSSRATE,EQOB,RPMA,RPMO,EQDB,SMAL,EQQI,OQQI,INDX,TQBR,TQOB,TQQI,TQDE,SPBFUT,SPBOPT,RTSIDX,CETS,INSTR,EQRP_INFO,TQIF,TQTF,INSTRCETS,'
qlua> getSecurityInfo("TQBR", "GAZP")
{ sec_code='GAZP', face_unit='SUR', class_code='TQBR', code='GAZP', scale=2, face_value=5, short_name='ГАЗПРОМ ао', lot_size=10, name='"Газпром" (ПАО) ао', min_price_step=0.01, isin_code='RU0007661625', class_name='МБ ФР: Т+ Акции и ДР', mat_date=20171220 }
qlua> function OnParam(c, s) 
   2> print(qluaDump(c, s, getParamEx2(c, s, "LAST")))
   3> end
qlua> 
и в терминал посыплются строки вида
Код
'TQBR', 'TRNFP', { param_type='1', param_value='178600.000000', result='1', param_image='178 600' }
'TQBR', 'VTBR', { param_type='1', param_value='0.046810', result='1', param_image='0,04681' }
'TQOB', 'SU24019RMFS0', { param_type='1', param_value='102.537000', result='1', param_image='102,5370' }
'CETS', 'EURUSD000TOM', { param_type='1', param_value='1.193400', result='1', param_image='1,193400' }
'TQOB', 'SU26219RMFS4', { param_type='1', param_value='102.300000', result='1', param_image='102,3000' }
'TQBR', 'SBER', { param_type='1', param_value='223.330000', result='1', param_image='223,33' }
'TQBR', 'SNGSP', { param_type='1', param_value='28.005000', result='1', param_image='28,005' }
'TQBR', 'RSTI', { param_type='1', param_value='0.820100', result='1', param_image='0,8201' }
'CETS', 'EURUSD000TOM', { param_type='1', param_value='1.193400', result='1', param_image='1,193400' }
'TQBR', 'AFLT', { param_type='1', param_value='138.950000', result='1', param_image='138,95' }
'TQBR', 'GAZP', { param_type='1', param_value='130.300000', result='1', param_image='130,30' }
'TQBR', 'HYDR', { param_type='1', param_value='0.727000', result='1', param_image='0,7270' }

Для остановки callback присваиваем ему nil (бесстрашно вводим код пока в терминале продолжается выхлоп от OnParam - в реале, конечно, нужно в файл выводить):
Код
qlua> OnPa ram = nil
qlua>
(выхлоп прекращается).  Ну и т.д.

Для завершения работы набираем "quit":
Код
qlua> quit
qlua terminated
Если вдруг по привычке нажмете кнопку "Остановить", то нужно будет в терминале нажать <Enter>, чтобы main() вышла из io.stdin:read() (не нашел изящного способа это побороть, не прибегая к внешним библиотекам).

Следует заметить, что локальные переменные видны только до следующего qlua> (они локальны внутри chunk), поэтому
Код
qlua> local v = 5
qlua> print(v)
nil
qlua>
Но:
Код
qlua> local v = 5; print(v)
5
qlua> do
   2> local v = 5
   3> print(v)
   4> end
5
qlua>
Все как и в обычном интерпретаторе Lua, запущеном в интерактивном режиме.
Функция criticalSection() для выполнения произвольного кода в потокобезопасном режиме
 
Пока в соседней ветке пытаюсь выяснить, как использовать table.ssort() по назначению, придумал ей применение во благо: функция criticalSection() ниже выполняет переданную ей функцию, предварительно заблокировав другой поток.

Важно: в своей функции, которую вы передаете в criticalSection(), ни в коем случае не вызывайте потокобезопасные функции, а используйте их стандартные версии.  Ваша функция может "бросать исключения" - финальный вариант это поддерживает.

Сама функция ниже, пример использования:
Код
local t1, t2 = {}, {}
local function insert(v1, v2)
   if v1 > v2 then error("v1 > v2") end

   t1.insert(v1)
   t2.insert(v2)

   return v1 + v2, v1 - v2
end

-- далее где-то в разных потоках "атомарно" вставляем оба значения
local r1, r2 = criticalSection(insert, a1, a2)
Функция (вам нужны первые две строки и финальный (последний) вариант, остальные в целях объяснения):
Код
-- В Lua 5.1 нет table.unpack, но есть unpack.
if not table.unpack then table.unpack = unpack end


-- Понятная версия.  На входе функция и ее аргументы (ноль или более),
-- переданная функция вызывается со своими аргументами под
-- блокировкой, на выходе все ее возвращаемые значения.
local function criticalSection(func, ...)
   -- Запаковываем аргументы для переданной функции в table.
   local args = {...}
   local res
   -- Функция "сравнения" для table.ssort() (передаваемые элементы
   -- упорядочиваемого массива игнорируются).
   local less = function()
      -- Распаковываем аргументы обратно в список, вызываем с ними
      -- переданную функцию, запаковываем результаты в table.
      res = { func(table.unpack(args)) }
      -- Говорим, что первый элемент упорядочиваемого массива меньше
      -- второго, то есть менять элементы местами не нужно.
      return true
   end
   -- "Упорядочиваем" массив из двух элементов (то есть наша функция
   -- "сравнения" вызовется ровно один раз), при этом во время вызова
   -- удерживается блокировка.
   table.ssort({ 0, 0 }, less)
   -- Распаковываем результаты обратно в список и возвращаем его.
   return table.unpack(res)
end


-- Слегка оптимизированная версия: массив { 0, 0 } создается только один
-- раз, функции unpack и ssort ищутся в модуле table также только один раз.
local criticalSection = (function()
   local unpack, ssort = table.unpack, table.ssort
   local array = { 0, 0 }
   return function(func, ...)
      local args = {...}
      local res
      local less = function()
         res = { func(unpack(args)) }
         return true
      end
      ssort(array, less)
      return unpack(res)
   end
end)()


-- Финальная версия: если внутри функции, переданной пользователем,
-- возникнет ошибка, то table.ssort() вылетит, не сняв блокировку (по
-- крайней мере так происходит в моей версии 7.5.0.72 - знаю, что
-- старая, но других брокер не дает).  Ниже код, решающий проблему -
-- на всякий случай именно его и следует использовать.
local criticalSection = (function()
   local unpack, ssort = table.unpack, table.ssort
   local array = { 0, 0 }
   local function pack(ok, ...) return ok, {...} end
   return function(func, ...)
      local args = {...}
      local ok, res
      local less = function()
         ok, res = pack(pcall(func, unpack(args)))
         return true
      end
      ssort(array, less)
      if ok then
         return unpack(res)
      else
         error(unpack(res), 0)
      end
   end
end)()
Потоковая безопасность в QLua - документация и реальность
 
Ниже несколько вопросов к поддержке и/или знатокам по теме потоковой безопасности.

Читаем документацию:
Цитата
Одновременная работа с таблицами из функций обратного вызова скрипта и функции main() может приводить к неопределенным ситуациям.
В языке Lua все переменные на самом деле являются ключами таблиц, называемых environments.  Присвоение ключу значения nil удаляет его из таблицы.  То есть, если в коде написано
Код
var = 5  -- глобальная переменная

function main()
   var = nil
end 
то это то же самое, что и
Код
_G["var"] = 5  -- глобальная переменная

function main()
   _G["var"] = nil
end 
(в новых версиях Lua вместо _G теперь _ENV, но не суть).  Видно, что функция main() удаляет ключ var из таблицы _G.
Вопрос 1: приводит ли присвоение nil глобальным переменным из функции main() (то есть не главного потока) к неопределенным ситуациям?

Читаем документацию дальше:
Цитата
Выполнение потокобезопасной функции блокирует выполнение кода в другом потоке до окончания работы функции.
Вопрос 2: имеется ввиду, что другие потоки блокируются при попытке вызвать (ту же или какую-то другую) потокобезопасную функцию (классическая critical section)?  Или же вообще все потоки волшебным образом останавливаются, ну, так, "на всякий случай"? :)

Еще читаем:
Цитата
В таблице представлены стандартные функции Lua и соответствующие им потокобезопасные аналоги:
concat   sconcat
remove  sremove
insert     sinsert
sort       ssort
Про table.sconcat() вопросов нет (ну хоть что-то понял! :)).  Думаем про table.ssort():
Код
local t = {}

function OnSomething(param)  -- какой-то callback
   table.sinsert(t, param)
end

function main()
   table.ssort(t)
   for _, v in ipairs(t) do
      print(v)
   end
end
Как только table.ssort() закончит работу другой поток может добавить новые данные - и у нас опять потенциально не упорядоченная таблица, которую мы и напечатаем.
Вопрос 3: как вообще тогда использовать table.ssort()?

Думаем про table.sinsert() и table.sremove():
Вопрос 4: в примере выше, что произойдет, если один поток изменит таблицу потокобезопасной функцией как раз в то время, когда другой поток находится где-то в дебрях интерпретатора Lua (внутри ipairs(), t[key], или еще где)?  Что именно сделано, чтобы все не "взорвалось"?  Или "так делать нельзя"?

Но предположим, что мы используемтолько потокобезопасные функции и другими способами к таблице не обращаемся, и реализуем классический message passing, то есть очередь сообщений между потоками:
Код
local mqueue = {}

function OnSomething(param)  -- какой-то callback
   while true do
      local msg = table.sremove(mqueue, 1)
      if not msg then break end
      -- обрабатываем сообщение msg (например, меняем логику работы этого callback)
   end
   -- обрабатываем param согласно (возможно новой) логике
end

function main()
   ...
   table.sinsert(<сообщение>)
   ...
end
Вопрос 5: а какие "сообщения" можно посылать таким образом?  Абсолютно любые "типы" Lua, или есть ограничения?  Этот вопрос связан со следующим:

Вопрос 6: а как потоки дружат со сборщиком мусора (garbage collector)?  Он один на все потоки, или по одному на каждый?  Если один, то в каком потоке выполняется, и что именно сделано, чтобы GC в одном потоке не "взорвал" другой работающий поток, и не "взорвался" сам, считая свободной память, которую другой поток как раз начинает использовать)?  Если же GC у каждого потока свой, то в случае message passing как в примере выше как именно передается ownership (то есть чей GC отвечает за рекламацию сообщения)?

Очень надеюсь получить ответы на все вопросы (и в особенности на 6-й) - хочется проникнуться доверием к реализации, управляющей моими активами. :)

Заранее спасибо!
Страницы: 1
Наверх