Модуль очереди для обмена между потоками
Модуль FIFO очереди для обмена данными между потоком терминала (колбеками) и потоком скрипта QLua.
-- Модуль работы с очередями колбеков
local queue =
{
-- Создать новую очередь FIFO
new = function(self)
self.__index = self
return setmetatable( { first = 0,
last = -1
},
self)
end, --------------------------------------------------------------------------------------------
-- Поместить значение в очередь
push = function(self,value)
local last = self.last + 1
self[last] = value
self.last = last
end, ---------------------------------------------------------------------------------------------
-- Изъять самое старое значение из очереди. Если очередь пуста, возвращается nil
pop = function(self)
local first = self.first
if first <= self.last then
local value = self[first]
self[first] = nil
self.first = first + 1
return value
end
end, ---------------------------------------------------------------------------------------------
-- Количество значений в очереди
size = function(self)
return self.last - self.first + 1
end ---------------------------------------------------------------------------------------------
}
Комментарии
Егор. Модель построения скриптов на qlua - двухпоточная. Грубо можно сказать так: есть 2 процессора, которые независимо друг от друга крутят два потока исполнения. Один поток - это колбеки. Второй - это функция скрипта main() и все что из нее вызывается.
Теперь представим ситуацию, что колбек onAllTrade складывает в таблицу trades все приходящие сделки. То есть использует функцию, например, table.insert, добавляя информацию в конец таблицы.
Второй поток (который main) берет из этой таблицы первую сделку и удаляет её, используя table.delete
Оба процесса работают совершенно независимо друг от друга - так устроен qlua.
При этом обязательно (когда-нибудь, не сразу) возникнет конфликт.
Пример:
Функция table.insert узнала длину таблицы trades. Допустим, она равна 5
В этот момент table.delete из потока main удаляет первую строку. Таким образом, длина таблицы становится равна 4.
Теперь table.insert продолжает свою работу и увеличивет длину таблицы на 1, записывая новую сделку на 6(!!!!) место.
Таким образом, рвется структура таблицы - элемент с номером 5 пуст.
Факт, что архитектура qlua использует потоки и при этом не является потокобезопасно й, относительно известный. Пока приходится строить очереди типа той, что приведена в статье.
В ближайшем будущем в qlua появятся функции типа table.sinsert, table.sremove, table.sforeach и некоторые другие, которые будут уже потокобезопасны ми и надобность в данном модуле отпадет. Но пока нужно использовать его.
надо видимо читать как:
... и удаляет её, используя table.remove
В основном вылеты при выставлении-сня тии ордеров и при более 40 "закрытых" ордерах в таблице Заявок.
Правда я делаю на с++.
function OnAllTrade(trad e)
q:push(trade)
end
function main()
q = queue:new()
while q:size() > 0 do
process(q:pop() )
end
end
Quik 7.5.0.72
Заранее спасибо.
С некоторых пор в qlua бвли добавлены функции table.s*()
Они позволяют потокобезопасно проводить некоторые действия с таблицами, что позволяет реализовать буфер обмена.
Для простых роботов их хватит. Однако у функций table.s*() есть один серьезный недостаток и я отказался от их использования в своих скриптах. Я использую нечто похожее на тот способ, который приведен в этой статье
Или я не понимаю вопрос?
Если вы счастливчик и ваша задача попадает в оставшиеся 1% - тогда и будете потеть с написанием очередей на С++...
Просто раньше мой код падал где-то за 5-10 мин, а с данной очередью работает дольше - может и час проработать.
Проблема думаю в том, push и pop должны вызываться из разных потоков строго по одному, а сейчас, видимо, происходит прерывание потока в push или pop и передача контроля другому. Проблему легко решить через crititcal section или mutex, но никак не могу найти как это реализовать в Lua.
то получается нужно убрать
localqueueа в других файлах написать require("queue" )
Local можно оставить, можно убрать и сделать глобальным - это на вкус...
Если очередь слишком активная, мы не перейдем эти границы в first или last, хм?
Это не целые числа, а doublefloat
Если здесь вещественный doublefloat используется для
local last = self.last + 1
то это вообще странно.
UPD:
www.lua.org/pil/2.3.html
всё я понял к чему вы клоните.
Да, таких больших чисел хватит с запасом))
RSS лента комментариев этой записи