Зависание QUIK

Страницы: 1 2 След.
RSS
Зависание QUIK
 
Добрый день.

QUIK 8.8.4.3. Стандартная схема оформления.
Иногда после нескольких дней работы зависает. При этом загрузка ЦП процессом 0
Сначала грешил на потокобезопасные функции. Но анализ логов показывает, что зависании происходит вне потокобезопасных функций (но это не точно ))
Можно ли по стеку определить последнюю вызванную QLua функцию?
Надо делать так, как надо. А как не надо - делать не надо.
 
Добрый день!
По скриншотам ответить на ваш вопрос, к сожалению, не сможем.

Просим выслать на почту нашей поддержки (quiksupport@arqatech.com) дамп процесса в момент зависания, архив рабочего места QUIK со скриптами, которые работали на момент появления ошибки, и подробное описание проблемы.
 
Цитата
Старатель написал:
Можно ли по стеку определить последнюю вызванную QLua функцию?
По второму можно, видимо, надо только на вкладке "модули" посмотреть базовый адрес lua53.dll, перебирать возможные варианты по скрину долго.
 
Anton, спасибо.
Скрытый текст
Что можно с этим сделать?

QUIK не совсем завис, а только основной поток находится в ожидании чего-то.
Один из скриптов в main периодически шлёт отладочную информацию через PrintDbgStr.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Что можно с этим сделать?
Можно сказать, что зависло в функции lua_pushstring, но это не главное, на ее месте в принципе могла быть и другая, скрипт встал в ожидание на lua_lock (первая строка в сорце) и встал намертво. Где-то этот лок захвачен и не выпущен, возможно, в одном из (других) скриптов, возможно, косячок в самом квике. В скрипте захватить лок и не выпустить можно, например, если присутствует бесконечная рекурсия, может и другие варианты есть. Модельный пример с бесконечной рекурсией (элементарнейший, практические варианты, конечно, не так очевидны)
Код
function so()
   return so()
end

function main()
   so()
end
Тут еще важно, есть ли в рекурсивном кольце вызовы си-функций, они будут периодически отпускать лок и квик намертво не зависнет, будет течь и тормозить только. Тот же пример с вызовом си-функции квик не вешает
Код
function so()
   sleep(0)
   return so()
end

function main()
   so()
end
Тот факт, что один из скриптов в мейне все же прорывается время от времени, идею о совсем уж дедлоке ломает, однако ж, как ни крути, скрипт (и весь квик) стоит на lua_lock.

Еще замечу, что в варианте с 5.3 схему синхронизации сильно поменяли, раньше была просто критическая секция одна на весь луа, теперь там позабавнее система, вот этот кусочек на дизасме
Код
mov qword ptr [...]
...
test rax, rax
je <skip next instruction>
call rax
немного показывает, как теперь сделано. Если установлена "функция синхронизации" (т.е. она не null), то она и вызывается, иначе синхронизация пропускается и все. Как-зачем-почему не знаю, догадками мусорить не буду.
 
Старатель, дополню. Квик хочет вызвать колбек OnAllTrade и заполняет для него табличку с очередной сделкой. Все данные из ТВС уже вытащены, почти вся табличка заполнена, в последнюю очередь квик создает вложенную табличку datetime, пытается воткнуть в нее строку "day" и в этот момент виснет на lua_pushstring, как написал выше. В общем, это все мало что дает, косяк где-то в синхронизации все равно.
 
Цитата
Anton написал:
Квик хочет вызвать колбек OnAllTrade и заполняет для него табличку с очередной сделкой. Все данные из ТВС уже вытащены, почти вся табличка заполнена, в последнюю очередь квик создает вложенную табличку datetime, пытается воткнуть в нее строку "day" и в этот момент виснет на lua_pushstring, как написал выше. В общем, это все мало что дает, косяк где-то в синхронизации все равно.
Anton, спасибо.
Скрытый текст

Скрытый текст
Первые два трейда - это видимо, два скрипта из трёх запущенных. Один из которых, как я написал, выше, раз в минуту шлёт отладочную информацию. Второй просто молча работает (вроде, работает).

А третий скрипт, я также предполагал, что застрял перед вызовом одного из колбеков, потому и не отображается в логе.
Что касается бесконечной рекурсии, то их нет в скрипте. И я почти на 100% уверен, что QUIK "завис" не из-за логической ошибки в скрипте.
За эту версию говорит также тот довод, что неоднократно похожая проблема наблюдалась на скриптах из этой темы.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
За эту версию говорит также тот довод, что неоднократно похожая проблема наблюдалась на скриптах из этой  темы .
Там совсем другая картина, квик пытается получить колбек через lua_getglobal и падает из-за access violation. В этой теме проблема аналогичная, только на вызове не OnAllTrade, а OnParam, в остальном один в один. Думал, как оно может случиться, придумал только одно: если колбек вызывает какие-то функции квика, в процессе обработки такой функции квик может получить новое сообщение и вызвать колбек (возможно, другой) рекурсивно. Удерживаемый лок здесь не поможет, поток-то тот же самый. В некоторый момент лимит си-вызовов будет превышен, луа бросит ошибку, квик прибьет скрипт (и его стейты, естественно), рекурсия начнет раскручиваться в обратную сторону, вытесненные колбеки попытаются продолжить работу, а стейтов уже нет, вот и access violation.

Здесь же видим типичный дедлок. Возможно, базовая природа в обоих случаях та же, просто проявления разные, смотря на каком этапе находится колбек в момент ошибки. Впрочем, это надо поверять тестами все, пока только гипотезы.
 
Цитата
Anton написал:
Где-то этот лок захвачен и не выпущен, возможно, в одном из (других) скриптов, возможно, косячок в самом квике.
7500 и 5364 - потоки двух скриптов. Они большую часть времени стоят на SleepEx. Один из них, известно точно, периодически просыпается и шлёт отладочную информацию. Так что, лок захвачен явно не ими.
А вот, где поток третьего скрипта, не пойму, может прибит уже?
Скрытый текст


Цитата
Anton написал:
Там совсем другая картина, квик пытается получить колбек через lua_getglobal и падает из-за access violation.
Помимо описанных ошибок и падений в теме, несколько раз были и зависания.
Но зависает не скоро, и написать демонстрационный скрипт, гарантированно приводящий к зависанию в течение разумного времени после запуска не представляется возможным.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
А вот, где поток третьего скрипта, не пойму, может прибит уже?
А и правда, где мейн-то от зависшего скрипта. Если прибит, то теория с прибитием скрипта "под ковром" получает плюсик в свою пользу.

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

Цитата
Старатель написал:
Но зависает не скоро, и написать демонстрационный скрипт, гарантированно приводящий к зависанию в течение разумного времени после запуска не представляется возможным.
Так вот и да. Как раз бесконечную рекурсию я и пробовал как способ захватить лок луа и не выпускать его, также пробовал насильно превысить лимит си-вызовов, но никаких падений-зависаний не словил, в этом случае квик все поймал и четко зачистил. Возможно, в более нагруженном окружении словил бы чего, дык это еще надо как-то устроить.
 
У меня тоже завис основной поток квика, последняя версия 8.8.4.3. Похоже проблема есть.
 
Александр, Добрый день!

Просим выслать архив рабочего места и работающие на момент зависания скрипты с описанием проблемы на почту нашей поддержки (quiksupport@arqatech.com)
 
Roman Azarov, У меня там скрипты на lua api написаны. Давайте я понаблюдаю еще и возможно более точно вам скажу. Но я вам выслал на почту dumps после вылета квика. Возможно это другая проблема.
 
Идея с рекурсией не подтверждается пока, потестил с перезаказами ТВС следующим скриптом
Код
local run = true
local tabid = nil
local rowid = nil
local counter = 0
local recursion_level = 0
local max_recursion_level = 0

function OnInit()
   tabid = AllocTable()
   if 0 == AddColumn(tabid, 1, 'recursion level', true, QTABLE_STRING_TYPE, 16) then
      DestroyTable(tabid)
      tabid = nil
      error("AddColumn failed")
   end
   if 0 == AddColumn(tabid, 2, 'counter', true, QTABLE_STRING_TYPE, 16) then
      DestroyTable(tabid)
      tabid = nil
      error("AddColumn failed")
   end
   if 0 == CreateWindow(tabid) then
      DestroyTable(tabid)
      tabid = nil
      error("CreateWindow failed")
   end
   rowid = InsertRow(tabid, -1)
   if -1 == rowid then
      DestroyTable(tabid)
      tabid = nil
      rowid = nil
      error("InsertRow failed")
   end
end

function OnAllTrade(v)
   recursion_level = recursion_level + 1
   counter = counter + 1
   if recursion_level > max_recursion_level then
      max_recursion_level = recursion_level
   end
   if tabid then
      SetCell(tabid, rowid, 1, tostring(max_recursion_level))
      SetCell(tabid, rowid, 2, tostring(counter))
   end
   recursion_level = recursion_level - 1
end

function OnStop()
   if tabid then
      local t = tabid
      tabid = nil
      DestroyTable(t)
      rowid = nil
   end
   run = false
end

function main()
   while run do
      sleep(1000)
   end
end
Результат - уровень рекурсии стоит 1 как влитой. Кому не лень прошу повторить упражнения, может где двоечка хотя бы выскочит, тогда будем знать, что хотя бы в принципе такое возможно. Также можно попробовать понагружать OnAllTrade перед выводом в таблицу чем-нибудь. Вариант sleep(100) попробовал, загружает квик до почти зависания, но это и логично, надо бы чем-нибудь поинтересней.
 
А почему она там должна выскочить? Если колбек выполняется, то там 1, а если висит основной поток, то, по идее, колбек не выполнится.
Либо, можно предположить, что после "отвисания" он просто вызовет все колбеки в очереди. Последовательно.
 
Цитата
Nikolay написал:
А почему она там должна выскочить?
Выше предположил, что если из колбека вызвать (не любую, естественно) функцию квика, то эта функция может (неожиданно для всех) дернуть GetMessage, получить уведомление о новых данных и тут же на радостях дернуть соответствующий колбек, в результате получим вложенное выполнение колбека внутри другого колбека. Вот и хотел такое поведение спровоцировать. Очереди колбеков, насколько понимаю, специальной нет, как сериализатор используется общая очередь виндовых сообщений основного потока, wt_de шлет туда сообщения о приехавших данных, основной поток их выбирает и тут же дергает соответствующие колбеки, т.е. да, после "отвисания" очередь будет обрабатываться в порядке прихода сообщений, тут вопрос, не может ли она "отвиснуть" внутри колбека.
 
Цитата
Anton написал:
Результат - уровень рекурсии стоит 1 как влитой.
Погонял ваш тест. Единичка осталась.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Anton написал:
Идея с рекурсией не подтверждается пока, потестил с перезаказами ТВС следующим скриптом
Код
   local  run  =   true 
 local  tabid  =   nil 
 local  rowid  =   nil 
 local  counter  =   0 
 local  recursion_level  =   0 
 local  max_recursion_level  =   0 

 function   OnInit ()
   tabid  =   AllocTable ()
    if   0   =  =   AddColumn (tabid,  1 ,  'recursion level' ,  true , QTABLE_STRING_TYPE,  16 )  then 
       DestroyTable (tabid)
      tabid  =   nil 
      error( "AddColumn failed" )
    end 
    if   0   =  =   AddColumn (tabid,  2 ,  'counter' ,  true , QTABLE_STRING_TYPE,  16 )  then 
       DestroyTable (tabid)
      tabid  =   nil 
      error( "AddColumn failed" )
    end 
    if   0   =  =   CreateWindow (tabid)  then 
       DestroyTable (tabid)
      tabid  =   nil 
      error( "CreateWindow failed" )
    end 
   rowid  =   InsertRow (tabid,  -  1 )
    if   -  1   =  =  rowid  then 
       DestroyTable (tabid)
      tabid  =   nil 
      rowid  =   nil 
      error( "InsertRow failed" )
    end 
 end 

 function   OnAllTrade (v)
   recursion_level  =  recursion_level  +   1 
   counter  =  counter  +   1 
    if  recursion_level  >  max_recursion_level  then 
      max_recursion_level  =  recursion_level
    end 
    if  tabid  then 
       SetCell (tabid, rowid,  1 , tostring(max_recursion_level))
       SetCell (tabid, rowid,  2 , tostring(counter))
    end 
   recursion_level  =  recursion_level  -   1 
 end 

 function   OnStop ()
    if  tabid  then 
       local  t  =  tabid
      tabid  =   nil 
       DestroyTable (t)
      rowid  =   nil 
    end 
   run  =   false 
 end 

 function   main ()
    while  run  do 
       sleep ( 1000 )
    end 
 end 
  
Результат - уровень рекурсии стоит 1 как влитой. Кому не лень прошу повторить упражнения, может где двоечка хотя бы выскочит, тогда будем знать, что хотя бы в принципе такое возможно. Также можно попробовать понагружать OnAllTrade перед выводом в таблицу чем-нибудь. Вариант sleep(100) попробовал, загружает квик до почти зависания, но это и логично, надо бы чем-нибудь поинтересней.
зачем Вы данные всех сделок собираете в таблицу QLUA - это же тормозуха.
Собирайте в таблицу луа, либо в массив на C и будет вам счастье.
 
Цитата
nikolz написал:
зачем Вы данные всех сделок собираете в таблицу QLUA
Ничего никуда не собираю, сижу примус починяю, а тут и добрый совет подоспел. Попал тксть под раздачу.
 
Цитата
Anton написал:
Цитата
nikolz написал:
зачем Вы данные всех сделок собираете в таблицу QLUA
Ничего никуда не собираю, сижу примус починяю, а тут и добрый совет подоспел. Попал тксть под раздачу.
тогда поясните, что вы делаете в функции колбека:
-------------------------------
function   OnAllTrade (v)
  recursion_level  =  recursion_level  +   1
  counter  =  counter  +   1
   if  recursion_level  >  max_recursion_level  then
     max_recursion_level  =  recursion_level
   end
   if  tabid  then
     SetCell (tabid, rowid,  1 , tostring(max_recursion_level))
     SetCell (tabid, rowid,  2 , tostring(counter))
   end
  recursion_level  =  recursion_level  -   1
end
-------------------------
 
Цитата
nikolz написал:
тогда поясните
Как можете видеть, при входе в OnAllTrade инкрементируется recursion_level, а при выходе - декрементируется. Таким образом, он содержит глубину рекурсии по OnAllTrade в данный момент. В свою очередь, max_recursion_level содержит максимально достигнутую глубину рекурсии за время работы скрипта. Первая выделенная строчка выводит max_recursion_level в таблицу квика. Вторая выводит простой счетчик вызовов OnAllTrade, дабы было видно, что скрипт не завис. Цель всех упражнений - втыкать перед выводом в таблицу различные функции взаимодействия с квиком (чем тормознутее, тем лучше) и смотреть, не получится ли в каком-то из вариантов уровень рекурсии больше единицы.
 
Цитата
Anton написал:
смотреть, не получится ли в каком-то из вариантов уровень рекурсии больше единицы.
В QUIK существующая cхема обработки колбеков следующая:
  1.  Существует единственный служебный поток, из которого запускаются потоки скриптов пользователя (main).
  2.  При запуске пользовательских скриптов выполняется регистрация объявленных в них колбеков.
  3.  Колбеки всех запущенных пользователем скриптов обрабатываются в служебном потоке последовательно, так как поток один. Если в нескольких пользовательских скриптах объявлен некоторый колбек (с одинаковым названием), то при возникновении соответствующего ему события, для каждого скрипта в его state запускается свой (объявленный) колбек и выполняется это в служебном потоке последовательно.  Таким образом никакие существующие пользовательские колбеки не могут обрабатываться параллельно.
   С учетом выше изложенного  всегда max_recursion_level = 1 и это подтверждает предложенный вами тестовый скрипт.
 
Цитата
TGB написал:
Таким образом никакие существующие пользовательские колбеки не могут обрабатываться параллельно.
А и речи не было про параллельно.
 
Цитата
Anton написал:
А и речи не было про параллельно.
Если речь шла об рекурсии, то в обработке Quik-ом колбеков ее тоже нет.
 
Похоже, источник проблемы - функция с переменным числом аргументов.
Возникает либо при вызове функции
Код
c(func, ...)
либо при формировании таблицы аргументов
Код
local arg = {...}

Код демонстрационного скрипта:
Код
local run = true

function c(func, ...)  
  local arg = {...}
end

local f1 = function() end
function OnAllTrade(alltrade)
  c(f1, alltrade)
end
function OnParam(class, sec)
end
function OnStop()
  run = nil
end

local f2 = function() end
function main()
    while run do
      for i = 1, 100 do
        c(f2, i, 1, 2, 3)
      end
      sleep(1)
    end
end
Надо делать так, как надо. А как не надо - делать не надо.
 
Код
local run
local file

local function log(s)
  file:seek('set')
  file:write(s)
  file:flush()
end

function c(func, ...)
  log('1')
  local arg = {...}
  log('2')
end

function OnInit(path)
  local err
  file, err = io.open(path..'.log', 'w+')
  if file == nil then
    message(err, 3)
  else
    run = true
  end
end
function OnAllTrade(alltrade)
end
function OnParam(class, sec)
end
function OnStop()
  run = nil
end


local f2 = function() end
function main()
  if not run then return end
    while run do
      for i = 1, 100 do
        log('0')
        c(f2, i, 1, 2, 3)
        log('3')
      end
      sleep(1)
    end
  file:close()
end
В логе:
Цитата
1
Как и в прошлый раз поток main скрипта прибит. Основной поток остался в состоянии ожидания.
Скрытый текст
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Похоже, источник проблемы - функция с переменным числом аргументов.
Здравствуйте.

 Я в соседней ветке обсуждения как-то уже написал https://forum.quik.ru/messages/forum10/message48194/topic5527/#message48194 что, похоже, многие проблемы версий QUIK >= 8.5...  вызваны некорректной реализацией QLua-VM. Ситуации, когда при падении функций, написанных на "чистом" QLua, пользователю не выдаются диагностические сообщения из самого QLua - это ошибки разработчиков языка QLua (отличного от нативного Lua, в части реализации управления памятью). Причем, скорее всего, это ошибки синхронизации при реализации потокобезопасного управления автоматической памятью QLua.  Такого рода ошибки "плавающие" и внешне похожи на сбои аппаратуры. Но могут быть программы, которые создают нагрузку, при которой эти ошибки возникают чаще обычного. Это, наверное, делает и ваш срипт. Я 15.08.20 послал поддержке свою программу, которая "роняет" QUIKи в интервале 5 минут (в разные моменты времени). А до этого отправил кучу дампов. Наверное, имеет смысл и вам туда же отправить ваш скрипт.
 
Старатель,  не желаете патченую qlua.dll запробовать со своими тестами? Заменил там все lua_checkstack(1) на lua_checkstack(16), кроме OnParam, с этой сходу не понял даже, что там вытворено такое, выглядит как (в том фильме). Если паранойя не мучает, качнуть можно здесь. У меня нынче брокера нет на связи, оффлайн я не могу ваши крэши воспроизвести, а без крэшей что с патчем, что без, работает одинаково.
 
Разобрался и с OnParam, это там компилятор начудил своих оптимизаций, у арки было 1 как везде, гыгы. Как оказалось, я не 16, а 256 везде понаставил, ну даже и лучше, чай не на контроллере выполняемся. Тут вариант 2 с патчем и на OnParam тоже.
 
ДокладАю. Приведенный здесь тест у меня не воспроизвелся, воспользовался тестом из этого поста, он у меня хорошо воспроизводится. На оригинальной qlua.dll вывалился с дампом (все того же вида) с первого перезаказа. На патченой четыре перезаказа (вот сейчас, на большой ТВС) отработал, полет нормальный. Особо нагружать боевой сервер я стесняюсь, так что для сбора статистики предлагаю заинтересованным коллегам повторить эксперименты у себя. Если подтвердится работоспособность в патченом виде, то причина разрушения луа-стека в inline-обертке lua_checkstack внутри qlua.dll, там захардкодили расширение стека на 1 слот. Патч меняет это значение на 256 и в одном месте на 63 (не хватило байт для опкода).
 
Получил ошибку
Цитата
stack overflow
в строке
Код
local arg = {...}
(Это с оригинальной qlua.dll пока)
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Anton написал:
Приведенный здесь тест у меня не воспроизвелся
Ну тут как повезёт: может и несколько дней проработать без зависаний.

Цитата
Anton написал:
не желаете патченую qlua.dll запробовать со своими тестами?
Погоняю с вашей библиотекой, посмотрим.

Цитата
Anton написал:
Особо нагружать боевой сервер я стесняюсь
Так можно на демке гонять.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Получил ошибку  
Цитата
stack overflow
в строке  
Код
   local  arg  =  { .. .}  
(Это с оригинальной qlua.dll пока)
Не, знаю, после долгого тестирования, QUIK ошибки накапливает или чё?
После перезапуска скрипта словил ошибку
Цитата
bad argument #2 to 'write' (string expected, got FILE*)
в строке
Код
file:write(s)

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

Но в боевом квике в реальных условиях всё же виснет на строке
Код
local arg = {...}
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Не, знаю, после долгого тестирования, QUIK ошибки накапливает или чё?
Каждый слот стека начинается с GCObject, а его первое поле это GCObject * next. То есть все луа-объекты связаны в списки, используемые коллектором для прибития зомбаков. Раз уж вы словили разрушение стека, все эти списки коллектора уже сломаны, так что он начнет творить непредсказуемые вещи. Плюс, вылезая за границы выделенной памяти (и не будучи пойманным), луа ломает также и списки аллокатора, так что опять же когда-то потом в непредсказуемом месте (может быть, через пару дней) случится внезапный крэшик, концов которого не найдешь.
 
А логические ошибки, когда в непредсказуемом месте вылезает nil, типа attempt to compare number with nil и т.п., они могут как-то в будущем повлиять? QUIK перегружать нужно?
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
А логические ошибки, когда в непредсказуемом месте вылезает nil, типа attempt to compare number with nil и т.п., они могут как-то в будущем повлиять? QUIK перегружать нужно?
Когда после ошибки в одном скрипте начинают сыпаться ошибки в других, или в нем же после рестарта, это показывает, что стек был покоцан, дальше уже как повезет, насколько сильно и т.д., где-то закончится небольшой утечкой, где-то уже серьезные повреждения, которые вылезут позже.

PS Не поделитесь содержимым ip.cfg от джуниора? Чет я его в виде архива не найду.
 
JUNIOR 1 [91.209.122.220:15100:info]
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
JUNIOR 1
Спасибо, прицепился. Ща потестируем от пуза.
 
Цитата
Anton написал:
Цитата
Старатель написал:
А логические ошибки, когда в непредсказуемом месте вылезает nil, типа attempt to compare number with nil и т.п., они могут как-то в будущем повлиять? QUIK перегружать нужно?
Когда после ошибки в одном скрипте начинают сыпаться ошибки в других, или в нем же после рестарта, это показывает, что стек был покоцан, дальше уже как повезет, насколько сильно и т.д., где-то закончится небольшой утечкой, где-то уже серьезные повреждения, которые вылезут позже.
Я про логические ошибки скрипта, когда где-то что-то недосмотрел, не проверил на nil полученные данные и т.п. И в какой-то момент вместо данных там оказался nil. Скрипт остановился. Это может повлиять на будущую работу?
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
И в какой-то момент вместо данных там оказался nil. Скрипт остановился. Это может повлиять на будущую работу?
В идеальном мире не должно, квик вызывает скрипты и колбеки под pcall, такие ошибки должны им отлавливаться и правильно обрабатываться. В реальном мире квик не всегда проверяет, когда ему из скрипта передан nil или битый указатель, лезет по ним и получает по ушам. Недавняя тема тому пример. Эти ошибки почему-то пролетают мимо pcall, в качестве костыля арка настроила вокруг pcall'а try-catch блок, и если ошибка долетела до него, скрипт принудительно прибивается прямо в ловушке. Проблема в том, что в этом случае вся постобработка в pcall обходится, то есть стек не выравнивается (одна из причин, видимо, почему в арке решили тут же скрипт прибивать, он уже и так не жилец), но главное не выпускается лок. С одной стороны, у каждого скрипта лок свой, раз скрипт прибили, то и проблем быть не должно, остался ли он захваченным или нет. С другой можно придумать (и изредка пронаблюдать) сценарий, в котором квик уже после прибития скрипта попытается что-то проделать в том же стейте, соответственно попробует захватить лок и повиснет на нем (а выпускать его уже некому). Это проблема отдельная, по-хорошему от костыля с ловушкой надо избавляться, а сначала расковырять все места, где квик наступает на мину в виде нила или битого указателя.
 
Чет увлекся деталями и краткого ответа по существу не написал. В общем, если ошибка (любая) была поймана pcall'ом, никаких разрушений в квике нет. Если поймана костыльной ловушкой, разрушения есть. Второе не значит, что дальше обязательно зависнет, все может быть хорошо, разве что утечет сколько-нибудь памяти (вряд ли много). В колбеках разница видна снаружи, пойманные pcall'ом ошибки скрипт не останавливают, только выводят сообщение, пойманные ловушкой - останавливают. С мейном сложнее, скрипт прибивается в любом случае. Сообщение ACCESS VIOLATION говорит о том, что поймала ловушка, типовое луа-сообщение типа не есть функция и подобные - это из pcall.
 
Старатель,  а вы тоже наблюдаете такой эффект: если много этих тестовых скриптов запущено, таблица всех сделок не успевает обновляться, перерисовывается изредка сразу с большим шагом. Но если кликнуть на каком-то меню, чтобы оно вылезло, таблица начинает рисоваться как обычно. Или открыть какой-нибудь модальный диалог, вроде заказа данных.

На новом джуне и ваших тестах получил кучку дампов и одно зависание с полпинка. После замены клуа на патченую перезаказываю уже который раз и пока все без эксцессов.

Для нехакеров замечу, что патченая длл для продакшена не предназначена, она патчена наскоро кое-как, чисто для тестов. Правильную длл сделает арка.
 
Цитата
Anton написал:
вы тоже наблюдаете такой эффект: если много этих тестовых скриптов запущено, таблица всех сделок не успевает обновляться, перерисовывается изредка сразу с большим шагом.
У меня в таблицу обезличенных сделок добавлен только один инструмент: либо какой-нибудь старый уже истёкший фьючерс либо какой-то неторговый. Т.ч., по факту само окно пустое, а сделки заказываю через фильтры (либо скриптом).
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Anton написал:
для сбора статистики предлагаю заинтересованным коллегам повторить эксперименты у себя
Первый тест: заменил длл вашей, подключился к серверу, запустил оба скрипта и, и почти сразу ошибка:
Цитата
attempt to compare number with function
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
и почти сразу ошибка
Этот тест у меня никак не хочет воспроизводиться, ни на оригинальной, ни на патченой. Весь сервер перезаказами издергал - ноль результата.
 
Следующий тест: запустил скрипт 1 и три скрипта 3 (дабы быстрее получить результат) с вашей патченой длл. Сделал несколько тестов.
Ошибки не дождался, т.к. QUIK зависал по уже знакомой схеме: main одного скрипта прибит, остальные скрипты крутятся, основной поток остался в состоянии ожидания.

Сейчас вышла версия 8.9. Посмотрим насколько она стабильнее.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Ошибки не дождался
У меня с патченой не было ни одного зависания/падения, гонял все тесты одновременно, перезаказывал по многу раз. Заменяешь на родную и достаточно быстро на тех же тестах что-нибудь ловишь. Кстати, патч только на колбеки, на SearchItems и потокобезопасные оставлено как есть. До них дорыться сложнее, все ж это пруф оф концепт, а не для работы.

Цитата
Старатель написал:
Сейчас вышла версия 8.9. Посмотрим насколько она стабильнее.
Одним глазком заглянул, lua_checkstack(1) на месте.
 
Anton, так и у меня может до нескольких дней без зависаний работать.
Но всё же проблема есть, в т.ч. в 8.9

Попробуйте следующий скрипт, также зависает:
Код
local run = true

local z = {0, 0}
local ssort = table.ssort
function OnAllTrade(alltrade)
  ssort(z, function () return true end)
end
function OnParam(class, sec)
end
function OnStop()
  run = nil
end

function f1()
  for k, v in pairs(_G) do end
end
local function f2()
  f1()
end
local function f3()
  f2()
end
local function f4()
  f3()
end

function main()
  while run do
    for i = 1, 50 do
      f4()
    end
    sleep(1)
  end
end

Зачем вложенные функции? Дело в том, что если использовать pairs непосредственно в цикле main, то скрипт раньше остановится с ошибкой
Цитата
invalid key to 'next'

Что делал, чтобы не ждать неделю и быстрее воспроизвести: заказал обезличенные сделки по всем инструментам, запустил три скрипта и по очереди каждый останавливал и запускал. Занятие довольно нудное, но результат будет быстрее.
Надо делать так, как надо. А как не надо - делать не надо.
 
Цитата
Старатель написал:
Попробуйте следующий скрипт
Попробую в течение нескольких дней, отпишусь по результатам.
 
Старатель, воспроизвел. Четыре скрипта завел, перезаказал твс, после второго стоп-старт квик слетел без дампа. Соответственно поковырять нечего, только догадки строить. Попробую еще дамп получить.
Страницы: 1 2 След.
Читают тему
Наверх