Germany | Finland | Saint Petersburg | Drive

Модуль очереди для обмена между потоками

Опубликовано в QLua

Модуль 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 ---------------------------------------------------------------------------------------------
}
Комментарии   
# Егор 20.01.2015 15:51
Зачем это нужно?
Ответить | Ответить с цитатой | Цитировать
# admin 20.01.2015 16:35
Цитирую Егор:
Зачем это нужно?


Егор. Модель построения скриптов на 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 и некоторые другие, которые будут уже потокобезопасны ми и надобность в данном модуле отпадет. Но пока нужно использовать его.
Ответить | Ответить с цитатой | Цитировать
# Alpinist573 21.09.2015 22:24
... и удаляет её, используя table.delete

надо видимо читать как:

... и удаляет её, используя table.remove
Ответить | Ответить с цитатой | Цитировать
# admin 22.09.2015 08:17
Да, конечно.
Ответить | Ответить с цитатой | Цитировать
# Егор 20.01.2015 16:58
Доступно объяснили. Спасибо. Видимо у меня из-за этого вылетает QUIK "c дампом". Ни как не могу отловить ошибку.
В основном вылеты при выставлении-сня тии ордеров и при более 40 "закрытых" ордерах в таблице Заявок.
Правда я делаю на с++.
Ответить | Ответить с цитатой | Цитировать
# Егор 20.01.2015 18:05
Еще бы пример, как этой очередью пользоваться?
Ответить | Ответить с цитатой | Цитировать
# admin 20.01.2015 18:28
Схематично:

function OnAllTrade(trad e)
q:push(trade)
end

function main()
q = queue:new()
while q:size() > 0 do
process(q:pop() )
end
end
Ответить | Ответить с цитатой | Цитировать
# Kalinin4 17.04.2015 22:54
Переписал по совету Михаила свой скрипт на полностью событийную модель. За основу решил взять этот код. Скрипт перестал взрываться по непонятным причинам.
Ответить | Ответить с цитатой | Цитировать
# AndreyPool 13.12.2016 11:04
Добрый день, подскажите для корректной работы main и OnTrade, OnStopOrder, OnOrder использование очереди ещё актуально? Или уже реализован другой механизм?
Quik 7.5.0.72
Заранее спасибо.
Ответить | Ответить с цитатой | Цитировать
# admin 13.12.2016 13:14
Здравствуйте

С некоторых пор в qlua бвли добавлены функции table.s*()

Они позволяют потокобезопасно проводить некоторые действия с таблицами, что позволяет реализовать буфер обмена.

Для простых роботов их хватит. Однако у функций table.s*() есть один серьезный недостаток и я отказался от их использования в своих скриптах. Я использую нечто похожее на тот способ, который приведен в этой статье
Ответить | Ответить с цитатой | Цитировать
# AndreyPool 13.12.2016 13:37
Спасибо за ответ. Очередь можно прописать внутри скрипта или создать отдельно как будет эффективнее?
Ответить | Ответить с цитатой | Цитировать
# admin 13.12.2016 14:22
Ээээ. Вот бы понять ваш вопрос. Очередь - это набор функций. Одна помещает значение в очередь, другая достаёт, остальные предоставляют какой-то сервис. Понятно, что эти функции есть часть вашего скрипта.

Или я не понимаю вопрос?
Ответить | Ответить с цитатой | Цитировать
# AndreyPool 13.12.2016 14:25
Создать отдельный dll файл и подключать его к основному скрипту или внутри основного скрипта функции прописать. Что будет эффективнее?
Ответить | Ответить с цитатой | Цитировать
# admin 13.12.2016 14:34
В 99% случаев разницы не будет. Поэтому имеет смысл использовать текст на луа.

Если вы счастливчик и ваша задача попадает в оставшиеся 1% - тогда и будете потеть с написанием очередей на С++...
Ответить | Ответить с цитатой | Цитировать
# AndreyPool 13.12.2016 14:38
Спасибо за совет)
Ответить | Ответить с цитатой | Цитировать
# Phil 02.02.2017 17:23
С данной очередью работает лучше, но все равно QUIK падает с Access Violation в qlua.dll.
Просто раньше мой код падал где-то за 5-10 мин, а с данной очередью работает дольше - может и час проработать.

Проблема думаю в том, push и pop должны вызываться из разных потоков строго по одному, а сейчас, видимо, происходит прерывание потока в push или pop и передача контроля другому. Проблему легко решить через crititcal section или mutex, но никак не могу найти как это реализовать в Lua.
Ответить | Ответить с цитатой | Цитировать
Добавить комментарий


Архив QLua