Здесь будут публиковаться кривые ошибки, возникающие, очевидно, из-за двухпоточной схемы работы QLua. Некоторые ошибки указаны здесь: Потокобезопасные функции в Lua 5.3
Надо делать так, как надо. А как не надо - делать не надо.
local run = true
function OnAllTrade(alltrade)
end
function OnParam(class, sec)
end
function main()
local getinfo = debug.getinfo
while run do
for i = 1, 100 do
getinfo(1)
end
sleep(1)
end
end
function OnStop()
run = nil
end
Ошибка в строке getinfo(1)
Цитата
bad argument #1 to 'getinfo' (number expected, got nil)
Надо делать так, как надо. А как не надо - делать не надо.
Никто и не обещал, что ошибка появляется всегда и сразу. Можно запустить несколько копий скрипта, как тут, сделать перезаказ обезличенных сделок... В общем, ошибка именно в этом коде и именно в этом месте присутствует. А как гарантированно воспроизвести - без понятия. Надо смотреть сорцы, откуда там nil.
Надо делать так, как надо. А как не надо - делать не надо.
Давненько я кривее ошибки не видел! Лет примерно 30-35! :)
Суть дела: написал я тестовый скрипт на Lua (чтобы разобраться, что здесь как работает - с языком до этого не сталкивался вообще). Тест заработал, я скопировал код в другой файл, уже почти "боевой", что-то там подрихтовал, запускаю - НЕ работает! Я стал сравнивать оба кода - НУ ВСЁ ТОЧНО ТАК ЖЕ! Проматерившись минут 40, я локализовал, наконец, место глюка. Из серии "не верь глазам своим". Вот полный код теста:
f=true function main() while f do sleep(5000) end message("Скрипт остановлен!") end
function OnStop() f=false end
Как оказалось, ошибка заключается в том (я миллион раз смотрел на это место!), что в "боевом" скрипте у меня стоит sleep(15000) - ну не нужно мне чаще! А эта скотина, как оказалось, через 5 секунд после останова принудительно завершает работу, "воруя" у меня управление. Читаю документацию - там стоит: [NUMBER time_out] OnStop(NUMBER signal) Что за "сигнал" - покрыто мраком, и в тестовых примерах никто его не использует, равно как и возвращаемое значение: флаг сбросили - что же тут возвращать? Ан нет - "Функция возвращает количество миллисекунд, которое дается скрипту на завершение работы", а по умолчанию у неё таймаут даётся именно в те самые 5 секунд! По этим словам тоже взгляд скользит, не задерживаясь - какое может быть "время для завершения", если у меня скрипт практически ничего не делает? А вот время на "безделье", на ожидание окончания последнего "sleep" - вынь, да положь! Короче, вот исправленный код, который корректно завершается даже при 15-секундной задержке:
local T = {}
function main()
while run do
...
for k, v in pairs(T) do -- тут ошибка
...
end
...
sleep(1)
end
end
stack traceback:
Цитата
in for iterator 'for iterator'
На момент возникновения ошибки таблица T была пуста: за время работы (3 часа) робота в таблицу элементы не добавлялись. Написать тестовый скрипт для воспроизведения или повторить ошибку не удалось.
Надо делать так, как надо. А как не надо - делать не надо.
local run = true
function OnAllTrade (alltrade)
end
function OnParam (class, sec)
end
function main ()
local getinfo = debug.getinfo
while run do
for i = 1 , 100 do
getinfo( 1 )
end
sleep ( 1 )
end
end
function OnStop ()
run = nil
end
Ошибка в строке getinfo(1)
Цитата
bad argument #1 to 'getinfo' (number expected, got nil)
К сожалению, нам не удалось понять причину проблемы. Рекомендуем использовать терминал версии 8.11 и Lua 5.4. Приносим извинения за причинённые неудобства.
Касательно последнего сообщения, ответим немного позже.
local T = {}
function main ()
while run do
.. .
for k, v in pairs(T) do -- тут ошибка
.. .
end
.. .
sleep ( 1 )
end
end
stack traceback:
Цитата
in for iterator 'for iterator'
На момент возникновения ошибки таблица T была пуста: за время работы (3 часа) робота в таблицу элементы не добавлялись. Написать тестовый скрипт для воспроизведения или повторить ошибку не удалось.
Проблема изучается. Постараемся в ближайшее время дать ответ.
В инструкции написано о довольно странной многопоточности. Действительно ли то, что многопоточность реализована путём патча виртуальной машины Lua в котором треды в любой момент времени могут очистить стек виртуальной машины и заполнить другими данными для начала исполнение колбека? Если это так, и если момент перехвата управления точно совпадает с моментом передачи аргументов в функцию, то возможна потеря аргументов если стек не был восстановлен корректно при завершении работы колбека.
Старатель, попробуйте запустить этот же код без колбеков.
Roman Azarov, Lua принципиально не поддерживает многопоточность, нативных средств реализации нет. В силу чего многопоточность Lua реализуют запуском отдельной виртуальной машины на каждый тред, и реализацией отправки данных между виртуальными машинами через C++, и вам тоже советую использовать такой-же метод. Один из простых методов реализации колбеков в однопоточном Lua заключается в том, чтобы писать колбеки в стек и сделать так, чтобы функция sleep вызывала колбеки и только после этого останавливала выполнение на оставшееся количество времени. Реализовывать можно прямо в Lua а не в C++.
Код
function sleep(ms)
local t1 = os.clock()
for cb, ... in _cplusplus_pollCallbacks() do
if type(_G[cb]) == 'function' then cb(...) end
end
_cpusplus_sleep(math.max(0, (os.clock() - t1) * 1000 - ms))
end
У вас тут повреждение стека виртуальной машины в случайные моменты времени, налицо наличие каких-то неочевидных ошибок в реализации многопоточности, и врядли у вас в команде есть программист С++ у которого IQ выше 180 чтобы этот баг можно было отловить и починить. Надо признать что интеллект до уровня Богов Олимпа всё-таки не дотягивает и решать проблему методами, которые под силу простому человеку.
Артем, Многопоточность достаточно тривиально реализуется на ЛЮБОМ языке - это разновидность программирования данными. Многопроцессность - с этим значительно сложнее, но тоже нет ничего "принципиально не поддерживаемого". Ну, а если "запускать отдельную виртуальную машину на каждый тред", то дурное дело нехитрое. А какой простор для труднонаходимых глюков!..
Оставьте хоть sleep в покое - чуть ли не единственное осталось, что пока работает!
Владимир, как товарищ Эйнштейн завещал: в теории, теория и практика это одно и тоже, но на практике, практика и теория сильно различаются. Так что то, что способ хорошо реализовать многопроцессность на Lua существует, еще не значит что кто-то его сможет найти в обозримом будущем. Ни один интерпретируемый язык не поддерживает работу на нескольких физических процессорах и изменения на этом фронте не предвидятся.
Артем, А при чём тут "работа на нескольких физических процессорах"? И одного вполне достаточно! Нет, "в обозримом будущем" действительно никто ничего не найдёт, я мало сомневаюсь. А вот "в обозримом прошлом" это особых проблем не составляло. Тоже мне бином Ньютона!(с) В частности, я сам делал нечно подобное на JS. А описание "нормального" монитора (сишного) приведено у меня в книге. Фрагмент:
Идея монитора довольно проста – он обслуживает процесс, то есть набор управляющих данных, представленных в виде стека очередей. Новая группа (объектов или событий) просто заносится как очередь (LIFO) на вершину стека (FIFO), т.е. очередь на вершине стека – это самые приоритетные на данный момент данные, которые обслуживаются по своей очереди «вне очереди». Ниже по стеку расположены те очереди, которые не будут обслужены до обработки всех верхних очередей стека. Собственно, именно так работает любой процессор: обслуживание текущей очереди определяется регистром счётчика команд, а выполнение вложенных процедур – регистром указателя стека. Для доступа к возвращаемым значениям методов используется стек аккумуляторов, устроенный аналогично стеку регистров сопроцессора, для неоднородных объектов – специальный стек системного уровня. Очередное событие из стека очередей обслуживается текущим обработчиком. Размер стека составляет обычно 64 очереди.
И далее:
У нас пока не возникало необходимости программирования многозадачных приложений, хотя техническая возможность создания нескольких процессов в рамках одного приложения имеется, и даже не очень сложна в реализации. Следует лишь помнить, что методы класса функции работают на одном и том же программном стеке, и при переключении процессов следует заботиться о сохранении и восстановлении данных этого стека.
Напоминаю, что каждое "ядро" это отдельный физический процессор. В домашних компьютерах как правило имеется всего 1 сокет и все процессоры монтируются на одном куске кремния, так что принято думать будто плата, на которой смонтировано десяток процессоров, это монолитный "процессор", а "ядра" это так, эфемерное понятие. На рабочих станциях и серверах распространены платы с 2, 4 и более сокетами под процессоры, и каждый процессор зачастую состоит из нескольких раздельных чипов, это проливает некоторый свет на идею многоядерности.
Владимир, не вижу связи с предметом разговора. Специально описывается система, которая работает последовательно на одном процессоре, без какой-либо параллельности. А у нас тут наоборот, проблема в том, что люди пытаются натянуть сову на глобус и заставить однопоточный Lua работать сразу на несколько процессоров, с ожидаемым результатом (вылеты скриптов на пустом месте).
Артем, Спасибо,я в курсе,что "каждое ядро это отдельный физический процессор". Представьте, что на компьютере один ОДНОЯДЕРНЫЙ процессор. Это ничуть не мешает организовать многопроцессную работу - примерно так, как я описал выше.
Не знаю, каким образом "люди пытаются натянуть сову на глобус и заставить однопоточный Lua работать сразу на несколько процессоров" (с их-то несчастными возможностями тупого интерпретируемого кода), но с "вылетами скриптов на пустом месте" я разобрался - больше не вылетает, исправил все свои ошибки и обвистовал чужие. А вот вылет самого Квика на ровном месте встречается всё чаще: несколько часов назад рухнул и сегодня у одного из брокеров (у которого версия 8.11 - у второго версия 8.8 работает уже несколько месяцев без нареканий). И эта тенденция мне СОВСЕМ не нравится! Кстати, этот брокер порекомендовал мне перейти на новую версию, которая оказалась 8.13, и началось такое, что торги вообще пришлось остановить! Завтра буду разбираться с брокером.
Queue = {
new = function (self)
return setmetatable({first = 1, last = 0}, {__index = self})
end,
push = function (self, v)
local last = self.last + 1
self[last] = v
self.last = last
return last
end,
pop = function (self)
local first = self.first
if first > self.last then return nil end
local v = self[first]
self.first = first + 1
self[first] = nil
return v
end,
size = function (self)
return self.last - self.first + 1
end
}
local OnAllTra des = Queue:new()
local function f(alltrade)
...
OnAllTrades:push(alltrade)
...
end
function OnAllTrade(alltrade)
... -- Во время ошибки параллельный поток находился где-то здесь
f(alltrade)
end
local run = true
function main()
while run do
...
if OnAllTrades:size() > 0 then
local alltrade = OnAllTrades:pop() -- Тут ошибка "attempt to call a nil value (method 'pop')"
...
end
end
end
Queue работает годами в разных скриптах. И (условно) раз в год (или реже) скрипты ругаются на nil. Было в 7-й или 6-й версии квика. Какое тогда было сообщение об ошибке не помню.
Скрытый текст
И ещё претензия к code highlighter на форуме: в строке 24
Код
local OnAllTra des = Queue:new()
он зачем-то добавляет пробел внутри слова
Надо делать так, как надо. А как не надо - делать не надо.
Queue = {
new = function (self)
return setmetatable({first = 1 , last = 0 }, {__index = self})
end ,
push = function (self, v)
local last = self.last + 1
self[last] = v
self.last = last
return last
end ,
pop = function (self)
local first = self.first
if first > self.last then return nil end
local v = self[first]
self.first = first + 1
self[first] = nil
return v
end ,
size = function (self)
return self.last - self.first + 1
end
}
local OnAllTra des = Queue:new()
local function f(alltrade)
.. .
OnAllTrades:push(alltrade)
.. .
end
function OnAllTrade (alltrade)
.. . -- Во время ошибки параллельный поток находился где-то здесь
f(alltrade)
end
local run = true
function main ()
while run do
.. .
if OnAllTrades:size() > 0 then
local alltrade = OnAllTrades:pop() -- Тут ошибка "attempt to call a nil value (method 'pop')"
.. .
end
end
end
Queue работает годами в разных скриптах. И (условно) раз в год (или реже) скрипты ругаются на nil. Было в 7-й или 6-й версии квика. Какое тогда было сообщение об ошибке не помню.
Скрытый текст И ещё претензия к code highlighter на форуме: в строке 24
Код
local OnAllTra des = Queue:new()
он зачем-то добавляет пробел внутри слова
Добрый день,
Действительно, в ПО QLUA есть ошибка функций обратного вызова скрипта приводящая к подобным ошибкам. Мы справим её в очередном обновлении ПО приносим извинения за причинённые неудобства.
Старатель написал: Старатель написал: local hour = 0+os.date('%H') выскочила такая ошибка: attempt to perform arithmetic on a nil value
Меня заинтриговала ошибка, которую вы обнаружили, в таком коротком коде. Напишите, пожалуйста: Как часто выполняется в скрипте приведенный вами фрагмент? Где это выполняется: в main или колбеках? -----------------------
Цитата
Старатель написал: Также ошибка attempt to call a nil value (method 'pop') в 9.1 никуда не пропала. Откуда здесь nil?
В вашем коде, по вашей ссылке, используется в двух потоках потоконебезопасная очередь OnAllTrades. В API QLua есть функции реализации потокобезопасной очереди, созданные разработчиком QUIK: table.sinsert, table.sremove. Пример использования потокобезопасной очереди: https://forum.quik.ru/messages/forum10/message56397/topic6356/#message56397
TGB написал: В API QLua есть функции реализации потокобезопасной очереди, созданные разработчиком QUIK: table.sinsert, table.sremove. Пример использования потокобезопасной очереди
В качестве разминки сделайте перезаказ обезличенных сделок (или переключитесь на другой сервер) ближе к концу торговой сессии и посмотрите, с какой задержкой будет обрабатываться ваша очередь и расход памяти скриптом. Задержка вычисляется как разница между временем получения колбека и фактическим временем обработки его в main.
Надо делать так, как надо. А как не надо - делать не надо.
TGB написал: В вашем коде, по вашей ссылке, используется в двух потоках потоконебезопасная очередь OnAllTrades. В API QLua есть функции реализации потокобезопасной очереди, созданные разработчиком QUIK: table.sinsert, table.sremove. Пример использования потокобезопасной очереди: https://forum.quik.ru/messages/forum10/message56397/topic6356/#message56397
На самом деле, push выполняется только в потоке коллбэков, pop и size -- только в main-потоке. Очередь, реализованная Старателем, в этом случае корректно работает и без блокировок.
Ошибки типа os.date() == nil означают, что где-то глубоко в QLua что-то не так. У меня подобное было в 2014-2015 годах, потом прошло и уже давно не было. Возможно, в 9-й версии опять что-то не так.
Старатель написал: В качестве разминки сделайте перезаказ обезличенных сделок (или переключитесь на другой сервер) ближе к концу торговой сессии и посмотрите, с какой задержкой будет обрабатываться ваша очередь и расход памяти скриптом.
Очередь не моя, а разработчика QUIK. Мне не известно как вы обрабатываете обезличенные сделки (сколько это может занимать ресурсов ПК), поэтому я запустил тест для проверки времени выполнения потокобезопасных функций реализации только очереди:
Код
---- Скрипт -тест ----
-- Этот фрагмент выполняется ~500 милисекунд ---
local T = {}
local v
for j = 1, 10 do
for i = 1, 1000 do --- запись в очередь
table.sinsert (T, {'sdfdfmffmf', 57})
-- v = T[1]
-- table.sremove(T, 1)
end
for i = 1, 1000 do --- чтение из очереди
-- table.sinsert (T, {'sdfdfmffmf', 57})
v = T[1]
table.sremove(T, 1)
end
end
10000 обращений (запись, чтение, удаление) за 500 миллисекунд. Понятно, что тест искуственный (без взаимодействия с колбеками), но какое то представление о скорости работы очереди и допустимой ее длине он дает. Заметного роста памяти QLua я не заметил.
Цитата
Старатель написал: Цитата TGB написал: В вашем коде, по вашей ссылке, используется в двух потоках потоконебезопасная очередь OnAllTrades. И?
Это значит, что при работе с такой очередью могут возникать ошибки синхронизации, которые могут порождать наблюдаемые вами последствия.
==========================
Цитата
_sk_ написал: Очередь, реализованная Старателем, в этом случае корректно работает и без блокировок.
Старатель написал: Абсолютно беспочвенное утверждение, говорящее об отсутствии понимания работы обсуждаемого кода.
Вы имеете ввиду, что для записи и чтения в очередь используются свои указатели и, я бы с вами согласился, если бы не существовал общий объект, в котором это происходит (таблица хранения очереди в которую вставляются и из которой вычеркиваются элементы очереди). Вы уверены, что работа с таблицей при изменении ее структуры в Lua реализована потокобезопасно? Где это написано?
TGB, если в представленном коде и возникают, как вы утверждаете, какие-то "ошибки синхронизации, которые могут порождать" пропажу метода pop, используемого только для чтения (!), то это уже вне зоны ответственности скриптера, а ошибка в реализации многопоточной модели QLUA.
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: Абсолютно беспочвенное утверждение, говорящее об отсутствии понимания работы обсуждаемого кода.
Вы имеете ввиду, что для записи и чтения в очередь используются свои указатели и, я бы с вами согласился, если бы не существовал общий объект, в котором это происходит (таблица хранения очереди в которую вставляются и из которой вычеркиваются элементы очереди). Вы уверены, что работа с таблицей при изменении ее структуры в Lua реализована потокобезопасно? Где это написано?
Разработчики ARQA, как я помню, утверждали с самого начала, что примитивные переменные и таблицы Lua не портятся при параллельном их изменении из разных потоков с помощью атомарных операций присваивания. Другое дело, что для таблиц это на самом деле может быть не так. Функции типа table.sinsert, table.sremove и т.п. пришлось вводить, т.к. они не атомарные и занимаются сдвигом внутренних элементов. Все ли подобные неатомарные штуки были "выловлены" разработчиками ARQA -- неизвестно. Если не все, то единственный адекватный вариант -- это создавать структуру в потоке коллбэков, потом table.sinsert, а в main-потоке делать table.sremove.
Теперь про "пропажу" функции pop(). Не исключаю, что время от времени терминал QUIK или операционная система занимаются неким "переносом данных внутри своей памяти" (например, при сборке мусора) во время которого оказывается, что функция pop ещё не определена (не успели её перенести) в новом месте, а её вызывают из другого потока. Но это уже мои домыслы.
Старатель написал: это уже вне зоны ответственности скриптера, а ошибка в реализации многопоточной модели QLUA.
1. Для устранения вашей конкретной ситуации, возможно, подойдет вариант реализации очередей, приведенный в моем комментарии https://forum.quik.ru/messages/forum10/message57219/topic6198/#message57219 2. Вообще, существует сравнительно несложный вариант заметно улучшить QLua (сделав его однопоточным для скриптера) без изменения его внутренней архитектуры: 1) добавить в API QLua функцию <задание схемы обработки колбеков>, которую скриптер может (но не обязательно) вызвать в начале своего скрипта с параметром задания схемы; если эта функция не вызвана, то колбеки обрабатывыются так, как это делается сейчас по старой схеме; дополнительно, в этой функции можно бы задавать версию Lua, а возможно и еще что-нибудь; при задании новой схемы, внутри QLua автоматически реализуется схема взаимодействия main с колбеками через две потокобезопасные эффективные очереди (как обеспечить их эффективность, наверное, понятно), одна из которых обслуживает колбеки фондового рынка, а вторая, колбеки событий таблиц QUIK, созданных скриптером; 2) при работе по новой схеме обработки колбеков, в API QLua добавить еще две функции: <функция подписки на события фондового рынка> и <функция подписки на события пользовательских таблиц >; в этих функциях скриптер может, в виде списка (в таблице) подписаться на события в соответствии с существующими именами колбеков; реализация подписки разработчиком QUIK может быть сведена к автоматическому созданию (скрытых) от пользователя функций колбеков, вызываемых, как это делается сейчас, и записывающих свои параметры с добавлением «от кого параметры» в соответствующие очереди; 3) для работы с очередями по новой схеме в API QLua добавить две функции чтения (?возможно также и выполнения некоторых дополнительных функций), соответственно очередям; при чтении очередей в считываемой таблице передаются: <имя события>, <время записи в очередь>, <параметры в том виде, как они описаны, в существующих колбеках>. При работе по второй схеме, QLua для скриптера становится однопоточным и снимаются многие сложные проблемы. Причем, остается возможность не затрагивать и тех скриптеров, которые по тем или иным причинам не станут уходить от старой схемы. ---- Общая схема работы скриптера в новой схеме обработки событий QUIK. <Заказывается новая схема обработки событий > <Выполняется подписка (вместо написания функций колбеков) на обрабатываемые события QUIK> <В функции main, в цикле читаются две очереди и обрабатываются считанные параметры событий> ------- Мною была описан некий, как мне представляется, не сильно сложный вариант реализации избавления QLua от проблем параллелизма, связанных с его существующей реализацией.
Старатель написал: local hour = 0+os.date('%H') выскочила такая ошибка: attempt to perform arithmetic on a nil value
Ошибка, которую вы обнаружили, замечательна своей локализацией (всего одна строка кода). --- Я посмотрел в исходниках Lua 5.3 код функции os.date и то, как она вызывается на исполнение в коде Lua. Этот код не блокирует потоки в текущей версии QLua 5.3 (и это легко проверить). При этом, os.date, формально, не является C-функцией, так как в внутри ее кода, без блокировки, используется среда исполнения Lua (ее внутренние функции), формально не гарантирующая корректного параллелизма при ее использовании. Это же относится к некоторым другим библиотечным функциям Lua, имеющим признак C-функций. В C-функциях можно использовать только C-API Lua. Использование внутренних функции Lua, без блокировки, в коде C-функций является ошибкой. В версии Lua 5.3 (а возможно и в 5.4), похоже, есть «дыра» в некоторых ее стандартных функциях, для работы с ними из разных потоков. При работе в однопоточном варианте Lua такая «дыра» проявить себя не может. Но, собственно, разработчики Lua не один раз заявляли, что поддерживают однопоточный вариант Lua, а остальное факультатив, с которым надо разбираться тем, кто встраивает Lua в свои решения. ------ Конечно, можно попытаться анализировать все коды стандартных функций с используемыми внутренними функциями Lua без блокировки («раскручивая» соответствующие цепочки вызовов внутренних функций Lua) с целью выяснения, вдруг, случайно, какие то, из них, корректны при работе в нескольких потоках. Но по-хорошему, при написании всех кодов модулей библиотечных функции Lua, из ее среды исполнения, должно быть доступно только ее API (обеспечивающее корректность обращения к Lua из разных потоков). В принципе, для разработчика QUIK есть простой вариант исправления, в исходниках QLua, стандартных функций с используемыми внутренними функциями Lua без блокировки: в начале кода таких функций выполняется lua_lock, а при выходах из них (! их может быть несколько) выполняется lua_unlock.
TGB написал: 10000 обращений (запись, чтение, удаление) за 500 миллисекунд.
Не смотря на то, что сам тест бестолковый, но холостой цикл за 0,5 сек не слишком ли много?
Цитата
TGB написал: Заметного роста памяти QLua я не заметил.
Таблица из 1000 строк длиной 10 байт каждая. Какой "рост" вы рассчитывали увидеть в таком тесте?
Цитата
TGB написал: Для устранения вашей конкретной ситуации, возможно, подойдет вариант реализации очередей, приведенный в моем комментарии
Это не моя ситуация, а разработчиков QLua )) И не увидел в вашем комментарии каких-то существенных отличий касательно использования метода pop(). Больше похоже на спам вашего OS_...
Надо делать так, как надо. А как не надо - делать не надо.
Старатель написал: И не увидел в вашем комментарии каких-то существенных отличий касательно использования метода pop().Больше похоже на спам вашего OS_...
Вы в комментарии https://forum.quik.ru/messages/forum10/message57219/topic6198/#message57219 читали это: 2. Существенная особенность построения очередей в OS_Quesha состоит в том, что они строятся на таблицах, в которых после их создания, нет вставок или удалений их полей (записей). В процессе работы с очередями изменяются только значения существующих полей, обеспечивающих запись/чтения этих очередей. Структура таблиц очередей «заморожена». Это обеспечивает в многопоточном режиме возможность эффективной синхронизации работы с очередями на уровне их полей, а не на глобальном уровне самих очередей. Так вот, эта существенная особенность обеспечивает то, что приведенный в комментарии конкретный код модуля Queue_safe создания очередей между колбеками и main является потокобезопасным в существующем QLua, в отличие от выложенного вами Queue, который потокобезопасным не является, о чем я уже писал в этой ветке.
TGB написал: TGB написал:10000 обращений (запись, чтение, удаление) за 500 миллисекунд.Не смотря на то, что сам тест бестолковый, но холостой цикл за 0,5 сек не слишком ли много?
Опять неточность (мы же обсуждаем код Queue_safe). В моем обсуждаемом коде Queue_safe во фрагменте тестирования указано: -- 1. Этот фрагмент (использование потокобезопасных функций QLua) (100 000 записей и чтений) выполняется за ~3560 милисекунд --- ................ -- 2. Этот фрагмент (использование Queue_safe) (100 000 записей и чтений) выполняется за ~55 милисекунд ---
Старатель написал: код в сообщении #24 в частности.
Выполненные мною в Lua 5.3 (5.4) тесты атомарности операций вставки/удаления полей в таблицу показали, что эти операции (в условиях реализован-ной многопоточности QLua) все-таки атомарны. Возможно?, есть ситуации, не охваченные тестированием, когда атомарности может не быть. Если же таких ситуаций нет, то мое утверждение, что выложенный Старателем код Queue (с описанием редко возникающей ошибки) создает потокоопасные очереди, ошибочное.