Потокобезопасные функции в Lua 5.3

Страницы: 1
RSS
Потокобезопасные функции в Lua 5.3
 
Скрипт 1:
Скрытый текст

Скрипт 2:
Скрытый текст

При запущенных обоих скриптах изредка в строке
Код
while #AllTrades > 0 do
возникает странная ошибка:
Цитата
attempt to compare number with function
Для воспроизведения можно Получить заново данные по обезличенным сделкам.
 
QUIK 8.8.1.5
Можно запустить несколько копий, чтобы наверняка.
 
Скрипт 1 оставляем. Скрипт 2 меняем на Скрипт 3:
Скрытый текст

Можно также запустить несколько копий, чтоб наверняка.
Изредка выскакивает ошибка
Цитата
bad argument #1 to 'ssort' (table expected, got nil)
в строке
Код
table.ssort({0, 0}, function()
Иногда падает.
Причём, может длительное время работать без сбоев. После появления первой ошибки и перезапуска скрипта, ошибки начинают сыпаться чаще.
 
По всем признакам разрушение стека луа. Второй вариант попробовал, словил дамп со второй попытки перезаказа, access violation. Поковырял его, что мы видим
Скрытый текст
Курсор на момент падения находится в функции lua53!auxgetstr(). Сама эта функция из lua53 не экспортируется, что-то еще по пути компилятор выбросил при оптимизации, видимо. Прошел по колстеку вверх, не нашел, чтобы где-то был лок захвачен перед вызовом, а сама функция, как внутренняя для луа, его не захватывает. Оно ничего не значит, конечно, не нашел и не захвачен разные вещи, накидываю как идею для арки, куда посмотреть.
 
Цитата
Anton написал:
не нашел, чтобы где-то был лок захвачен перед вызовом
Наврал, на auxgetstr был джамп из lua_setfield(), а там все хорошо с локом. Отмена воздушной тревоги. Но значит упало на lua_setfield.
 
Еще раз поправлюсь. Падает на lua_getglobal. В qlua.dll основным потоком квика вызывается некая функция, она пытается вызвать lua_getglobal(state, "OnAllTrade") и, если успешно, далее заполняет табличку all_trade и вызывает полученную луа-функцию. То есть это как раз место, где вызывается OnAllTrade. В дампе крэш происходит вот где
Код
LUA_API int lua_getglobal (lua_State *L, const char *name) {
  Table *reg = hvalue(&G(L)->l_registry);
  lua_lock(L);
  return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); // <----------- HERE
}
а еще точнее вот где
Код
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
  const TValue *slot;
  TString *str = luaS_new(L, k);
  if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
    setobj2s(L, L->top, slot);
    api_incr_top(L);
  }
  else {
    setsvalue2s(L, L->top, str); // <-------------------------------------------- HERE
    api_incr_top(L);
    luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
  }
  lua_unlock(L);
  return ttnov(L->top - 1);
}
с сообщением
Код
Unhandled exception at 0x000007fef3d6420f in info_20200817_223941.dmp: 0xC0000005: Access violation writing location 0x0000000001882900.
То есть lua_getglobal что-то (функцию OnAllTrade или nil) извлекает из реестра, пытается засунуть на вершину текущего стека, а туда нельзя писать. Осталось догадаться, а почему собсна нельзя-то, то ли стек реаллоцирован (как? все же под локом), то ли весь стейт (опять - как? все же под локом), то ли страница памяти недоступна. Последнее звучит глупо, но там дальше вызов колбека идет с установкой se_translator, это наводит на мысль, что могла случиться рекурсия под транслятором и in-page-error была неожиданно слопана. Мож попробовать транслятор заменить на явный SEH-фрейм и ловить в нем только то, что стоит ловить?
 
Скрипт 4
Скрытый текст

Запускаю несколько копий. Делаю перезаказ обезличенных сделок. Предполагается, что все скрипты обработают одинаковое количество сделок.
Ан, нет. Спустя чуть больше часа разрываю соединение, чтобы проверить. Часть скриптов потеряла по одной сделке.
Скрытый текст
 
Ложная тревога. Скрипт 4 написан некорректно, потому сделки теряются.
 
Вопросы к разработчикам:

1) Исправлены ли в версии терминала 8.8.4 ошибки, описанные в этой теме?

2) Если ответ на п.1 отрицательный, то смогли ли вы воспроизвести эти ошибки у себя?
 
добавлю свои пять копеек.
Если это особенности VMLua то разработчики ничего исправлять не будут.
VMLua написана не ими. Они лишь встраивают ее в КВИК и сделали dll интерфейса на луа с хранилищем терминала и обменом с сервером КВИК.
---------------------
Проблема многопоточности в луа - это проблема луа.
Есть различные решения этой проблемы, но они никак не связаны с КВИК.
 
Цитата
nikolz написал:
Если это особенности VMLua
Что я выше описал, это на стороне qlua.dll, то есть аркино производство. В самой lua53.dll правки если и есть, то крайне незначительные, практически все строка в строку ложится на сорцы луа из репозитория, как выше из разбора дампа видно.

Цитата
nikolz написал:
Проблема многопоточности в луа - это проблема луа.
Луа дает lua_lock/lua_unlock и на этом его проблемы с многопоточностью закончены. Можно поспорить, здорово ли, что в некоторых функциях 5.3 вытащили часть обращений к стеку из-под лока, если говорить о проблемах луа. Но вот как сделаны эти самые локи (и не только), это уже вопросы к арке.
 
Цитата
Anton написал:
Цитата
nikolz написал:
Если это особенности VMLua
Что я выше описал, это на стороне qlua.dll, то есть аркино производство. В самой lua53.dll правки если и есть, то крайне незначительные, практически все строка в строку ложится на сорцы луа из репозитория, как выше из разбора дампа видно.

Цитата
nikolz написал:
Проблема многопоточности в луа - это проблема луа.
Луа дает lua_lock/lua_unlock и на этом его проблемы с многопоточностью закончены. Можно поспорить, здорово ли, что в некоторых функциях 5.3 вытащили часть обращений к стеку из-под лока, если говорить о проблемах луа. Но вот как сделаны эти самые локи (и не только), это уже вопросы к арке.
Ва заблуждаетесь,
если бы все было так просто, то проблему многопоточности в луа не поднимали бы на форумах  уже лет ..надцать.
Вот, например, результат попытки решения критическими секциями (look, unlook)
и таких воплей в инете много.
--------------------
Тоже решал эту проблему, но не уверен, что нашел окончательное решение .
 
https://zen.yandex.ru/media/id/5d1e1629b4a58500acbc079a/mnogopotochnost-v-lua-moia-glavnaia-oshibka-...
 
Цитата
nikolz написал:
если бы все было так просто, то проблему многопоточности в луа не поднимали бы на форумах  уже лет ..надцать.
Это именно проблемы многопоточности как таковой, а не многопоточности в луа. В приведенной статье тоже. Как раз автор пришел в конце к правильному выводу, асинхронность рулит. Надо только не забывать, что нынче практически все процессоры многоядерные, даже контроллеры многие, так что многопоточность все равно будет присутствовать, главное ее локализовать и не позволить ей разползтись по всему коду. Конкретно в квике уже отступать некуда, архитектура выбрана такая и трудно предположить, как ее можно обратно-совместимо поправить. Теперь только костыли лепить.

Цитата
nikolz написал:
Тоже решал эту проблему
Многие решали, в том числе и основоположники. К сожалению, конкретно в их решении очереди блокирующие, эдакий qnx получился.
 
Цитата
Anton написал:
Цитата
nikolz написал:
если бы все было так просто, то проблему многопоточности в луа не поднимали бы на форумах  уже лет ..надцать.
Это именно проблемы многопоточности как таковой, а не многопоточности в луа. В приведенной статье тоже. Как раз автор пришел в конце к правильному выводу, асинхронность рулит. Надо только не забывать, что нынче практически все процессоры многоядерные, даже контроллеры многие, так что многопоточность все равно будет присутствовать, главное ее локализовать и не позволить ей разползтись по всему коду. Конкретно в квике уже отступать некуда, архитектура выбрана такая и трудно предположить, как ее можно обратно-совместимо поправить. Теперь только костыли лепить.

Цитата
nikolz написал:
Тоже решал эту проблему
Многие решали,  в том числе и основоположники . К сожалению, конкретно в их решении очереди блокирующие, эдакий qnx получился.

Дискуссия схоластическая, но замечу, что Вы путаете понятия
Проблема многопоточности и проблема синхронизации потоков - это синонимы. т е первое это есть второе.
Проблема именно луа а не многопоточности.
Как решать задачу синхронизации потоков в конкретном софте хорошо разжевано у Рихтера.
Но в луа проблема в том, что есть сборщик мусора и много сторонних библиотек.
--------------------------
Вы не внимательно прочитали статью, на которую ссылаетесь.
---------------------------
цитата: "В этой работе мы исследуем модель, основанную на выполнении потоков без общей памяти, которые используют передачу сообщений для синхронизации и общения."
Т е это фактически многозадачное решение, а не многопоточное.
------------------------------
и далее цитата:
"Связь между процессами Lua происходит исключительно через сообщения. Cвязь с передачей сообщений может быть медленнее по сравнению с общей памятью."
===============  
Т е упрощенно, запускаем несколько независимых VMLua как несколько задач, а потом пересылаем данные между ними в виде сообщений OC.
Проблемы такого решения хорошо известны.
 
 
Цитата
nikolz написал:
Дискуссия схоластическая
Есть такое.

Цитата
nikolz написал:
Проблема многопоточности и проблема синхронизации потоков - это синонимы.
Да, так. Надо пойти дальше и спросить, а в чем проблема синхронизации потоков. Она в синхронизации доступа к данным и только. У каждого потока есть свой (нативный) стек, поток также может выделить tls из кучи, и если он никуда больше не ходит, ему никакая синхронизация не требуется. Как только появляется какое-то разделяемое между потоками состояние, возникает проблема синхронизации доступа к нему. Посмотрим на примере. Берем два потока, совместно использующих один int. Если потоки лезут в этот int без синхронизации, имеем проблемы (даже int с точки зрения процессора не атомарен, атомарно можно его прочитать, но модифицировать уже нет). Защищаем int критической секцией. Все, проблем нет. Но если у нас два разделяемых int'а, появляется выбор: одна общая критическая секция на все разделяемое состояние или у каждого поля своя. Второй вариант это отличный способ огрести проблем: во-первых, появляется возможность дедлока, во-вторых, появляется проблема атомарности изменения обоих полей сразу. То есть лучше выбрать вариант раз с одной критической секцией на все разделяемое состояние, ценой более длительных блокировок всех потоков. В луа самом по себе вариант раз и использован, но есть нюансы*. А в квике получился вариант два, результаты которого в основном и вылезают то тут то там. Внутри квика это еще можно разрулить, зная, что и в каком порядке лочить, но как только к этой запутанной системе дан доступ внешнему кодеру через луа, открыт ящик пандоры, кодер завсегда придумает, как упорядочить свои обращения к состоянию так, чтобы повесить весь квик или получить неконсистентные результаты. Автор топика не раз просил арку дать возможность синхронизации из луа, но это, увы, не решит проблему, в квике нет одного общего лока на все, а еще один лок сделает только хуже.

Радикальный способ решения проблем - как раз приведенный в статье, межпоточное взаимодействие, по определению требующее синхронизации, локализуется в виде очередей сообщений, а каждый поток работает только со своим состоянием и ему никакая дополнительная синхронизация не нужна в принципе. Это еще не процессы (луа-то общий и нативный процесс тоже общий, хоть авторы и выбрали путающую терминологию), это просто собрали всю синхронизацию в одном месте и избавили конечного кодера от размышлений о ней. Как конкретно решили мне не нравится, но путь правильный.

Цитата
nikolz написал:
Проблемы такого решения хорошо известны.
Можно ссылок или ключевиков? Винда как-то работает на сообщениях и ничего страшного, даже порт завершения позже придумали, то есть вперли-таки сообщения в само ядро (и молодцы).


* Если посмотреть в сорцы луа, увидим прекрасную вещь: сам по себе интерпретатор всегда работает под локом (пруф: поищите lua_lock /lua_unlock в этой функции). То есть, если выполняется только луа-код без вызовов функций, он весь атомарен (и другие потоки ждут). Лок снимается только перед вызовом си-функции. При этом встроенные библиотеки луа тоже состоят из си-функций, поэтому лок может быть снят (и тут же захвачен снова библиотечной функцией) в непредсказуемых местах, что убивает-таки атомарность изменения состояния как целого даже в луа без квика, при этом средств синхронизации со стороны луа не предоставлено. То есть луа защищает консистентность своего состояния, но не консистентность состояния пользовательского кода, с точки зрения луа-кодера он в той же ситуации, в какой и без луа, вот тебе потоки и рули как хочешь. Поэтому и говорю, что проблема не луа-специфичная, проблема в ожиданиях от луа чего-то, чего он не дает, хоть в нем и есть lua_lock.
 
Цитата
Anton написал:
Падает на lua_getglobal. В qlua.dll основным потоком квика вызывается некая функция, она пытается вызвать lua_getglobal(state, "OnAllTrade") и, если успешно, далее заполняет табличку all_trade и вызывает полученную луа-функцию. То есть это как раз место, где вызывается OnAllTrade.
Где вы это смотрите?
 
Цитата
Старатель написал:
Где вы это смотрите?
Дамп загружается в вижл студию и запускается на отладку, будет показан колстек, а дальше сопоставляем дизасм с сорцами луа и вычисляем, где какая функция. Достаточно просто с некоторым навыком. Были б символы от квика, было б вообще просто, да кто ж их даст )
 
А у вас студия открывает дамп, созданный диспетчером задач?
 
Цитата
Старатель написал:
А у вас студия открывает дамп, созданный диспетчером задач?
Да, открывает.
 
Цитата
Anton написал:
Цитата
nikolz написал:
Дискуссия схоластическая
Есть такое.

Цитата
nikolz написал:
Проблема многопоточности и проблема синхронизации потоков - это синонимы.
Да, так. Надо пойти дальше и спросить, а в чем проблема синхронизации потоков. Она в синхронизации доступа к данным и только. У каждого потока есть свой (нативный) стек, поток также может выделить tls из кучи, и если он никуда больше не ходит, ему никакая синхронизация не требуется. Как только появляется какое-то разделяемое между потоками состояние, возникает проблема синхронизации доступа к нему. Посмотрим на примере. Берем два потока, совместно использующих один int. Если потоки лезут в этот int без синхронизации, имеем проблемы (даже int с точки зрения процессора не атомарен, атомарно можно его прочитать, но модифицировать уже нет). Защищаем int критической секцией. Все, проблем нет. Но если у нас два разделяемых int'а, появляется выбор: одна общая критическая секция на все разделяемое состояние или у каждого поля своя. Второй вариант это отличный способ огрести проблем: во-первых, появляется возможность дедлока, во-вторых, появляется проблема атомарности изменения обоих полей сразу. То есть лучше выбрать вариант раз с одной критической секцией на все разделяемое состояние, ценой более длительных блокировок  всех  потоков. В луа самом по себе вариант раз и использован, но есть нюансы*. А в квике получился вариант два, результаты которого в основном и вылезают то тут то там. Внутри квика это еще можно разрулить, зная, что и в каком порядке лочить, но как только к этой запутанной системе дан доступ внешнему кодеру через луа, открыт ящик пандоры, кодер завсегда придумает, как упорядочить свои обращения к состоянию так, чтобы повесить весь квик или получить неконсистентные результаты. Автор топика не раз просил арку дать возможность синхронизации из луа, но это, увы, не решит проблему, в квике нет одного общего лока на все, а  еще один лок  сделает только хуже.

Радикальный способ решения проблем - как раз приведенный в статье, межпоточное взаимодействие, по определению требующее синхронизации, локализуется в виде очередей сообщений, а каждый поток работает только со своим состоянием и ему никакая дополнительная синхронизация не нужна в принципе. Это еще не процессы (луа-то общий и нативный процесс тоже общий, хоть авторы и выбрали путающую терминологию), это просто собрали всю синхронизацию в одном месте и избавили конечного кодера от размышлений о ней. Как конкретно решили мне не нравится, но путь правильный.

Цитата
nikolz написал:
Проблемы такого решения хорошо известны.
Можно ссылок или ключевиков? Винда как-то работает на сообщениях и ничего страшного, даже порт завершения позже придумали, то есть вперли-таки сообщения в само ядро (и молодцы).


* Если посмотреть в сорцы луа, увидим прекрасную вещь: сам по себе интерпретатор всегда работает под локом ( пруф: поищите lua_lock /lua_unlock в этой функции ). То есть, если выполняется только луа-код без вызовов функций, он весь атомарен (и другие потоки ждут). Лок снимается только перед вызовом си-функции. При этом встроенные библиотеки луа тоже состоят из си-функций, поэтому лок может быть снят (и тут же захвачен снова библиотечной функцией) в непредсказуемых местах, что убивает-таки атомарность изменения состояния как целого даже в луа без квика, при этом средств синхронизации со стороны луа не предоставлено. То есть луа защищает консистентность своего состояния, но не консистентность состояния пользовательского кода, с точки зрения луа-кодера он в той же ситуации, в какой и без луа, вот тебе потоки и рули как хочешь. Поэтому и говорю, что проблема не луа-специфичная, проблема в ожиданиях от луа чего-то, чего он не дает, хоть в нем и есть lua_lock.
Возможно ваши рассуждения правильны, возможно нет.
Но это не имеет значение, так как решения проблемы нет, кроме как указанная вами ссылка - т е созданием изолированных задач.

Я достаточно подробно изучал  исходники луа,  что решить проблему много поточности в своих приложениях и ускорения обмена данными из луа в си.
кое что получилось, не утверждаю, что все.

Можно много рассуждать и строить правдоподобные гипотезы о том  , почему что-то не работает.
но это лишь трата времени на переливание из пустого в порожнее, если не доказано как это исправить.
 
Цитата
nikolz написал:
если не доказано как это исправить
На мой взгляд, тут исправлять ничего не нужно, кроме известных косяков. Свет клином не сошелся на qlua, его возможностей достаточно, чтобы вытащить нужные данные и ввести заявки, а все остальное можно делать снаружи, не загоняясь конкретной реализацией луа в квике, привычным, хорошо натренированным способом для конкретного исполнителя. Либо, если надо модифицировать поведение самого квика (что уже подразумевает некоторую хачность решения и привязку к версии), qlua дает официальный способ затащить в процесс длл и даже получать некоторые полезные уведомления. Если не пытаться строить космический корабль из запорожца, то все нормально. Опять же это то же самое создание изолированных задач, и это хорошая архитектура, если, конечно, нет желания переписывать все и вся под каждую новую версию квика.

Цитата
nikolz написал:
Я достаточно подробно изучал  исходники луа,  что решить проблему много поточности в своих приложениях и ускорения обмена данными из луа в си.
По-любому все потоки в квике, привязанные к луа, будут шарить одну луа-машину и, таким образом, выполняться по очереди. Поэтому я не понимаю цели подобных изысканий. Ну, создали еще 100 потоков, получили 100 дополнительных переключений контекста, поймали и героически преодолели кучку косяков с синхронизацией. И в чем профит? Кроме, конечно, прокачивания скилла, тоже занятие не сказать чтобы вредное, если есть куда потом этот скилл продать.
 
Цитата
Anton написал:
На мой взгляд, тут исправлять ничего не нужно, кроме известных косяков. Свет клином не сошелся на qlua, его возможностей достаточно, чтобы вытащить нужные данные и ввести заявки, а все остальное можно делать снаружи, не загоняясь конкретной реализацией луа в квике, привычным, хорошо натренированным способом для конкретного исполнителя. Либо, если надо модифицировать поведение самого квика (что уже подразумевает некоторую хачность решения и привязку к версии), qlua дает официальный способ затащить в процесс длл и даже получать некоторые полезные уведомления. Если не пытаться строить космический корабль из запорожца, то все нормально. Опять же это то же самое создание изолированных задач, и это хорошая архитектура, если, конечно, нет желания переписывать все и вся под каждую новую версию квика.
очевидные, почти аксиоматичные вещи, но реальность такова, что начитанные не всегда или очень не сразу становятся разумными
се ля ви
пс: хотя конечно без дурачков типа бурхановича было бы не так весело
 
Цитата
Anton написал:
По-любому все потоки в квике, привязанные к луа, будут шарить одну луа-машину и, таким образом, выполняться по очереди. Поэтому я не понимаю цели подобных изысканий. Ну, создали еще 100 потоков, получили 100 дополнительных переключений контекста, поймали и героически преодолели кучку косяков с синхронизацией. И в чем профит? Кроме, конечно, прокачивания скилла, тоже занятие не сказать чтобы вредное, если есть куда потом этот скилл продать.
По-моему Вы ошибаетесь.
VMLua (луа машин)  не одна, а одна+число скриптов.
Одна - в основном потоке, где будут последовательно вызываться все колбеки QLUA
и еще по одной на каждый скрипт (main - создает свою VMLua)
-------------------------------
В итоге колбеки QLUA вызываются в очередь, а потоки main могут работать параллельно.
Поэтому, если мы делаем копию получаемых данных, то их обработка может выполнятся параллельно.
------------------  
Но в отличии от запуска независимых задач, нет надобности перебрасывать все данные во все параллельные задачи.
В том то и суть параллельных потоков.
Если мы строит робота, который работает со множеством инструментов, то запуск отдельного скрипта (main) на каждый инструмент, позволяет нам организовать параллельную работу с инструментами.
При этом большинство модулей будет универсальными и будут запущены в единственном экземпляре.
-----------------
В существующем варианте QLUA  в каждом скрипте для различных инструментов надо повторять все колбеки QLUA .
В итоге мы получаем многократный вызов одних и тех же колбеков в различных скриптах.
----------------  
В моем варианте для 1000 инструментов будет один модуль обработки например ТТП
А в существующей версии QOUA  таких вызовов будет 1000 на каждое изменение ТТП  и все они будут вызываться последовательно.
В итоге получается ужас какой-то.
Страницы: 1
Читают тему (гостей: 1)
Наверх