Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки. В с++ я бы использовал mutex, в lua я нашел подобие mutex (возможно ошибаюсь), функции: https://www.lua.org/manual/2.1/section3_5.html
но я не понимаю как их использовать и не могу найти примеры (судя по объявлению функций это вообще с++). Подскажите как можно решить проблему или где найти примеры/описание?
Решение очень простое: не используйте одни и те же данные в разных потоках. Один из примеров практической реализации такого принципа это двойная буферизация.
Есть следующий "хак", гарантирующий, что выполнение кода будет только в одном потоке.
Код
table.ssort({ 0, 1 }, function(a, b)
тут_ваш_код
return true
end)
Идея в том, что выполняется "бесполезный" ssort на таблице из двух элементов с указанным компаратором. Ваш код выполнится один раз внутри этого компаратора.
Только не надо злоупотреблять этим, иначе терминал начнёт тормозить.
Артем написал: Код, не вызывающий никаких С-функций, выполняется атомарно. Так что можно использовать глобальные переменные в качестве мутексов.
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так: 1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep. 2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так: 1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep. 2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
Да. Тут надо уточнить что использование динамической памяти тоже снимает лок - создание новых объектов и строк. При использовании полностью статической памяти и отсутствии манипуляции строк, лок не должен сниматься. Еще надо уточнить что каждый луа-скрипт имеет свой отдельный тред, но колбеки выполняются из главного треда квика, так что пока колбек (любой из них) выполняется или стоит в ожидании, весь терминал будет висеть.
Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки.
Поскольку вы используете потокобезопасные функции, то добавление элемента в конец таблицы (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Надо делать так, как надо. А как не надо - делать не надо.
Поскольку вы используете потокобезопасные функции, то добавление элемента в конец таблицы (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Удаление влечет последствия: 1 поток нашел, что ему нужно удалить запись с индексом 5 но пока не удалил 2 поток удалил запись с индексом 3 1 поток удаляет запись с индексом 5 - это уже не та запись, которую он нашел - это проблема.
Sergey написал: Прошу помочь в синхронизации потоков.
В документе разработчика QUIK: «Использование Lua в Рабочем месте QUIK.pdf», в разделе «2. Взаимодействие потоков Lua скрипта» описана рекомендуемая схема обработки колбеков. Если придерживаться ее, то проблем многопоточности (! из-за того, что колбеки запускаются в потоке отличном от потока main) в скрипте пользователя не будет. По ссылке https://forum.quik.ru/messages/forum10/message56397/topic6356/#message56397 вы найдете пример из раздела «2. Взаимодействие потоков Lua скрипта».
_sk_ написал: Есть следующий "хак", гарантирующий, что выполнение кода будет только в одном потоке.
Код
table.ssort ({ 0 , 1 }, function (a, b)
тут_ваш_код
return true
end )
Запускаю одновременно два скрипта. Использую "хак", рассчитывая, что скрипты будут писать в файл по очереди:
Скрытый текст
Код
local f
function OnInit()
f = assert(io.open(getScriptPath() .. "\\file.txt", "a"))
end
function main()
table.ssort({0, 1}, function ()
for i = 1, 100 do
f:write("1\n")
f:flush()
end
return true
end)
f:close()
end
Код
local f
function OnInit()
f = assert(io.open(getScriptPath() .. "\\file.txt", "a"))
end
function main()
table.ssort({0, 1}, function ()
for i = 1, 100 do
f:write("22\n")
f:flush()
end
return true
end)
f:close()
end
table.ssort захватывает лок луа и не позволяет переключить поток с мейна на основной поток квика (или обратно). Между скриптами он не работает, у каждого скрипта свой лок.