Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки. В с++ я бы использовал mutex, в lua я нашел подобие mutex (возможно ошибаюсь), функции:
но я не понимаю как их использовать и не могу найти примеры (судя по объявлению функций это вообще с++). Подскажите как можно решить проблему или где найти примеры/описание?
Пользователь
Сообщений: Регистрация: 03.02.2021
30.06.2021 05:12:26
Решение очень простое: не используйте одни и те же данные в разных потоках. Один из примеров практической реализации такого принципа это двойная буферизация.
Пользователь
Сообщений: Регистрация: 24.06.2021
30.06.2021 08:11:53
Спасибо, за ответ. А потоки синхронизировать в Lua можно?
Пользователь
Сообщений: Регистрация: 31.01.2015
30.06.2021 08:19:40
Есть следующий "хак", гарантирующий, что выполнение кода будет только в одном потоке.
Код
table.ssort({ 0, 1 }, function(a, b)
тут_ваш_код
return true
end)
Идея в том, что выполняется "бесполезный" ssort на таблице из двух элементов с указанным компаратором. Ваш код выполнится один раз внутри этого компаратора.
Только не надо злоупотреблять этим, иначе терминал начнёт тормозить.
Пользователь
Сообщений: Регистрация: 24.06.2021
30.06.2021 08:32:41
Спасибо!
Пользователь
Сообщений: Регистрация: 03.02.2021
30.06.2021 10:01:05
Цитата
Sergey написал: Спасибо, за ответ. А потоки синхронизировать в Lua можно?
Код, не вызывающий никаких С-функций, выполняется атомарно. Так что можно использовать глобальные переменные в качестве мутексов.
Пользователь
Сообщений: Регистрация: 24.06.2021
30.06.2021 13:14:14
Цитата
Артем написал: Код, не вызывающий никаких С-функций, выполняется атомарно. Так что можно использовать глобальные переменные в качестве мутексов.
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так: 1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep. 2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
Пользователь
Сообщений: Регистрация: 03.02.2021
30.06.2021 23:47:21
Цитата
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так: 1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep. 2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
Да. Тут надо уточнить что использование динамической памяти тоже снимает лок - создание новых объектов и строк. При использовании полностью статической памяти и отсутствии манипуляции строк, лок не должен сниматься. Еще надо уточнить что каждый луа-скрипт имеет свой отдельный тред, но колбеки выполняются из главного треда квика, так что пока колбек (любой из них) выполняется или стоит в ожидании, весь терминал будет висеть.
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
13.07.2021 08:33:02
Цитата
Sergey написал: В нее добавляются и из нее удаляются элементы в потоке main и колбеках функциями:
Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки.
Поскольку вы используете потокобезопасные функции, то добавление элемента в конец таблицы (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Надо делать так, как надо. А как не надо - делать не надо.
Поскольку вы используете потокобезопасные функции, то добавление элемента в конец таблицы (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Удаление влечет последствия: 1 поток нашел, что ему нужно удалить запись с индексом 5 но пока не удалил 2 поток удалил запись с индексом 3 1 поток удаляет запись с индексом 5 - это уже не та запись, которую он нашел - это проблема.
Пользователь
Сообщений: Регистрация: 30.01.2015
Роботорговец
13.07.2021 13:37:22
Цитата
Sergey написал: 2 поток удалил запись с индексом 3 1 поток удаляет запись с индексом 5 - это уже не та запись, которую он нашел - это проблема.
Если оба потока удаляют записи в таблице, то да, нужна синхронизация.
Надо делать так, как надо. А как не надо - делать не надо.
Пользователь
Сообщений: Регистрация: 12.05.2020
13.07.2021 15:53:37
Цитата
Sergey написал: Прошу помочь в синхронизации потоков.
В документе разработчика QUIK: «Использование Lua в Рабочем месте QUIK.pdf», в разделе «2. Взаимодействие потоков Lua скрипта» описана рекомендуемая схема обработки колбеков. Если придерживаться ее, то проблем многопоточности (! из-за того, что колбеки запускаются в потоке отличном от потока main) в скрипте пользователя не будет. По ссылке вы найдете пример из раздела «2. Взаимодействие потоков Lua скрипта».
Пользователь
Сообщений: Регистрация: 30.05.2020
23.10.2021 16:19:09
Цитата
_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 захватывает лок луа и не позволяет переключить поток с мейна на основной поток квика (или обратно). Между скриптами он не работает, у каждого скрипта свой лок.