Синхронизация потоков

Страницы: 1
RSS
Синхронизация потоков
 
Добрый день.
Прошу помочь в синхронизации потоков.
Есть глобальная таблица
Код
Trades = {}
В нее добавляются и из нее удаляются элементы в потоке main и колбеках функциями:
Код
table.sremove(Trades, i) 
table.sinsert(Trades, trade)

Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки. В с++ я бы использовал mutex, в lua я нашел подобие mutex (возможно ошибаюсь), функции:
https://www.lua.org/manual/2.1/section3_5.html
Код
int        lua_lock (void);
lua_Object lua_getlocked  (int ref);
void       lua_pushlocked (int ref);
void       lua_unlock (int ref);
но я не понимаю как их использовать и не могу найти примеры (судя по объявлению функций это вообще с++).
Подскажите как можно решить проблему или где найти примеры/описание?
 
Решение очень простое: не используйте одни и те же данные в разных потоках. Один из примеров практической реализации такого принципа это двойная буферизация.
 
Спасибо, за ответ. А потоки синхронизировать в Lua можно?
 
Есть следующий "хак", гарантирующий, что выполнение кода будет только в одном потоке.

Код
table.ssort({ 0, 1 }, function(a, b) 
  тут_ваш_код
  return true
end)

Идея в том, что выполняется "бесполезный" ssort на таблице из двух элементов с указанным компаратором. Ваш код выполнится один раз внутри этого компаратора.

Только не надо злоупотреблять этим, иначе терминал начнёт тормозить.
 
Спасибо!
 
Цитата
Sergey написал:
Спасибо, за ответ. А потоки синхронизировать в Lua можно?
Код, не вызывающий никаких С-функций, выполняется атомарно. Так что можно использовать глобальные переменные в качестве мутексов.
 
Цитата
Артем написал:
Код, не вызывающий никаких С-функций, выполняется атомарно. Так что можно использовать глобальные переменные в качестве мутексов.
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так:
1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep.
2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
 
Цитата
Поясните пожалуйста, если main с бесконечным циклом без С-функций, в конце каждой итерации sleep это будет работать так:
1. Если выполняется код до sleep и приходит колбэк, то колбэк не будет выполняться, пока не начнет выполняться sleep.
2. При начале выполнения sleep, начнут выполняться накопленные колбеки, при этом в основном потоке дальше sleep выполнение не пойдет, пока не выполнятся все накопленные колбеки?
Да. Тут надо уточнить что использование динамической памяти тоже снимает лок - создание новых объектов и строк. При использовании полностью статической памяти и отсутствии манипуляции строк, лок не должен сниматься. Еще надо уточнить что каждый луа-скрипт имеет свой отдельный тред, но колбеки выполняются из главного треда квика, так что пока колбек (любой из них) выполняется или стоит в ожидании, весь терминал будет висеть.
 
Цитата
Sergey написал:
В нее добавляются и из нее удаляются элементы в потоке main и колбеках функциями:
Код
table.sremove (Trades, i) 
table.sinsert (Trades, trade)  

Проблема в том, что перед добавлением/удалинием элементов происходит перебор элементов таблицы в цикле для поиска нужного индекса. Если нужный элемент найден, а другой поток удалит элемент с меньшим индексом, то индексы сдвинутся и получится ерунда, т.е. нужно синхронизировать потоки.

Поскольку вы используете потокобезопасные функции, то добавление элемента в конец таблицы (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:

Поскольку вы используете потокобезопасные функции, то добавление элемента  в конец таблицы  (именно такая запись без указания индекса table.sinsert(Trades, trade)) не влечет каких-то неприятных последствий.
Удаление влечет последствия:
1 поток нашел, что ему нужно удалить запись с индексом 5 но пока не удалил
2 поток удалил запись с индексом 3
1 поток удаляет запись с индексом 5 - это уже не та запись, которую он нашел - это проблема.  
 
Цитата
Sergey написал:
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 )  

Запускаю одновременно два скрипта. Использую "хак", рассчитывая, что скрипты будут писать в файл по очереди:
Скрытый текст

Но в файле строки оказываются вперемешку:
Скрытый текст

Почему так? "Хак" не работает с файловыми операциями?
 
Цитата
Незнайка написал:
Почему так?
table.ssort захватывает лок луа и не позволяет переключить поток с мейна на основной поток квика (или обратно). Между скриптами он не работает, у каждого скрипта свой лок.
Страницы: 1
Читают тему
Наверх