Статус транзакции. Возможные значения: «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() (первые два для limit_kind >= 0, внутренние не особо интересны)? Кто-нибудь встречал эти вызовы в реале?
Кстати, а зачем вызываются ползовательские callbacks с limit_kind < 0? Какие осмысленные действия он бы мог сделать (хотя бы в теории)?
Сейчас в выдаче getQuoteLevel2() массивы bid и offer упорядочены по цене, но в документации это не упомянуто. Гарантируется ли такая упорядоченность, или опираться на это нельзя? Заранее спасибо за ответ!
Написал себе скрипт для интерактивной работы с QLua, возможно пригодится кому-то еще (иногда бывает нужно что-то быстро попробовать не строча полноценный скрипт). Код лежит на GitHub (хотел разместить прямо здесь, но (по крайней мене при нажатии кнопки "Просмотр") в случайных местах кода появлялись символы пробела - не понял, почему).
Для использования запускаем Quik из командной строки. То есть открываем окошко для ввода команд, пишем:
Далее из Quik запускаем qlua-console.lua, в терминале появляется приглашение для ввода. Можно исполнять любой код Lua, вызывать функции QLua и определять callbacks. Дополнительно доступна функция qluaDump(...) - возвращает строковое представление переданных аргументов. Например:
Для остановки 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, запущеном в интерактивном режиме.
Пока в соседней ветке пытаюсь выяснить, как использовать 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)()
Ниже несколько вопросов к поддержке и/или знатокам по теме потоковой безопасности.
Читаем документацию:
Цитата
Одновременная работа с таблицами из функций обратного вызова скрипта и функции 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-й) - хочется проникнуться доверием к реализации, управляющей моими активами. :)