Берём следующий скрипт. Если в первой строке стоит flag = true, то скрипт нормально запускается и останавливается из меню скриптов. Если в первой строке поставить flag = false, происходит зависание терминала при остановке скрипта. В зависимости от значения переменной flag либо имеется sleep(0) в функции main(), либо отсутствует на пути выполнения кода.
У меня зависание воспроизводится в терминалах версий 10.0.0 и 10.0.1.
Три вопроса: 1) Может ли кто-то ещё подтвердить, что зависание происходит (чтобы исключить особенность моего компьютера)? 2) Знает ли кто-то причину такого поведения? 3) Что разработчики терминала могут сказать по этому поводу?
Сам скрипт:
Код
local flag = true -- если установить в false, то при остановке скрипта происходит зависание (убирается sleep(0) в функции main)
local foregroundColor = RGB(0, 0, 0)
local backgroundColor = RGB(192, 255, 192)
local interrupted = false
local tableId
local function setTableColors(foregroundColor, backgroundColor)
local nRows, nCols = GetTableSize(tableId)
if nRows and nCols then
for row = 1, nRows do
for col = 1, nCols do
SetColor(tableId, row, col,
backgroundColor, foregroundColor,
backgroundColor, foregroundColor)
end
end
end
end
local function ensureWindowOpened()
if tableId == nil then
return
end
if IsWindowClosed(tableId) then
CreateWindow(tableId)
SetWindowPos(tableId, 0, 0, 300, 100)
SetWindowCaption(tableId, "hang_test")
InsertRow(tableId, 1)
InsertRow(tableId, 2)
SetCell(tableId, 1, 1, "11")
SetCell(tableId, 1, 2, "12")
SetCell(tableId, 2, 1, "21")
SetCell(tableId, 2, 2, "22")
SetSelectedRow(tableId, 1)
end
setTableColors(foregroundColor, backgroundColor)
end
local function closeWindow()
local t = tableId
tableId = nil
if t then
DestroyTable(t)
end
end
function OnInit(scriptPath)
tableId = AllocTable()
AddColumn(tableId, 1, "col1", true, QTABLE_STRING_TYPE, 5)
AddColumn(tableId, 2, "col2", true, QTABLE_STRING_TYPE, 5)
SetTableNotificationCallback(tableId, function(tId, msg, par1, _)
if msg == QTABLE_SELCHANGED then
SetSelectedRow(tId, 1)
end
end)
ensureWindowOpened()
end
local function run()
ensureWindowOpened()
if tableId then
SetSelectedRow(tableId, 2)
end
end
function OnStop(flag)
pcall(closeWindow)
interrupted = true
end
function main()
message("STARTED", 1)
while not interrupted do
run()
if flag then
sleep(0)
end
end
pcall(closeWindow)
message("SHUTDOWN", 1)
end
_sk_ написал: 2) Знает ли кто-то причину такого поведения?
Проверил у себя в песочнице 10.1. Ваш скрипт зависает при flag = false. Как известно, длинный участок фрагмента кода скрипта на "чистом Lua" в main (без вызова C-функций) блокирует выполнение потока обслуживающего колбеки. Функция sleep(0) - это C-функция. Когда вы исключаете ее исполнение (в цикле), то получается бесконечный фрагмент скрипта на "чистом Lua" и OnStop, являющийся колбеком не может быть выполненным.
_sk_ написал: 2) Знает ли кто-то причину такого поведения?
Проверил у себя в песочнице 10.1. Ваш скрипт зависает при flag = false. Как известно, длинный участок фрагмента кода скрипта на "чистом Lua" в main (без вызова C-функций) блокирует выполнение потока обслуживающего колбеки. Функция sleep(0) - это C-функция. Когда вы исключаете ее исполнение (в цикле), то получается бесконечный фрагмент скрипта на "чистом Lua" и OnStop, являющийся колбеком не может быть выполненным.
Тут с OnStop какая-то проблема, как мне кажется.
Заменяем фрагмент с кодом OnStop() вот на такое:
Код
function OnAllTrade(t)
message("OnAllTrade", 1)
end
function OnStop(flag)
message("OnStop executed", 1)
pcall(closeWindow)
interrupted = true
end
Проверяем ещё раз и видим, что: 1) коллбэки OnAllTrade выполняются (есть такие сообщения, если терминал получает обезличенные сделки); 2) при остановке скрипта терминал зависает, но при этом видно последнее сообщение "OnStopExecuted".
В принципе, вместо OnAllTrade можно любой другой коллбэк поставить (OnQuote, OnParam).
_sk_ написал: Тут с OnStop какая-то проблема, как мне кажется.
Причину я описал в своем комментарии. В вашем скрипте эта причина проявляется следующим образом. В цикле функции main есть два фрагмента кода с вызовами C-функций. Это sleep(0) и косвенно вызываемые (с помощью функции run()) стандартные функции работы с таблицами QUIK. При отключении sleep(0) остаются C-функции работы с таблицами QUIK. Поэтому OnStop запускается в потоке обработки колбеков (с выдачей сообщения "OnStop executed"). Но далее запускается pcall(closeWindow). В функции closeWindow отключается фрагмент работы с таблицами QUIK. Исполняемый код цикла функции main при этом представляет код на "чистом Lua". Внутри исполнения pcall(closeWindow) существует вызов C-функции (я с этим уже разбираться не буду), при котором блокируется поток обработки колбеков, но отпускается поток main, где в цикле выполнения кода на "чистом Lua" блокируется поток выполняемый функцию OnStop. QUIK виснет.
_sk_ написал: Тут с OnStop какая-то проблема, как мне кажется.
Причину я описал в своем комментарии. В вашем скрипте эта причина проявляется следующим образом. В цикле функции main есть два фрагмента кода с вызовами C-функций. Это sleep(0) и косвенно вызываемые (с помощью функции run()) стандартные функции работы с таблицами QUIK. При отключении sleep(0) остаются C-функции работы с таблицами QUIK. Поэтому OnStop запускается в потоке обработки колбеков (с выдачей сообщения "OnStop executed"). Но далее запускается pcall(closeWindow). В функции closeWindow отключается фрагмент работы с таблицами QUIK. Исполняемый код цикла функции main при этом представляет код на "чистом Lua". Внутри исполнения pcall(closeWindow) существует вызов C-функции (я с этим уже разбираться не буду), при котором блокируется поток обработки колбеков, но отпускается поток main, где в цикле выполнения кода на "чистом Lua" блокируется поток выполняемый функцию OnStop. QUIK виснет.
_sk_ написал: Берём следующий скрипт. Если в первой строке стоит flag = true, то скрипт нормально запускается и останавливается из меню скриптов. Если в первой строке поставить flag = false, происходит зависание терминала при остановке скрипта. В зависимости от значения переменной flag либо имеется sleep(0) в функции main(), либо отсутствует на пути выполнения кода.
У меня зависание воспроизводится в терминалах версий 10.0.0 и 10.0.1.
Три вопроса: 1) Может ли кто-то ещё подтвердить, что зависание происходит (чтобы исключить особенность моего компьютера)? 2) Знает ли кто-то причину такого поведения? 3) Что разработчики терминала могут сказать по этому поводу?
Сам скрипт:
Код
local flag = true -- если установить в false, то при остановке скрипта происходит зависание (убирается sleep(0) в функции main)
local foregroundColor = RGB ( 0 , 0 , 0 )
local backgroundColor = RGB ( 192 , 255 , 192 )
local interrupted = false
local tableId
local function setTableColors (foregroundColor, backgroundColor)
local nRows, nCols = GetTable Size (tableId)
if nRows and nCols then
for row = 1 , nRows do
for col = 1 , nCols do
SetColor (tableId, row, col,
backgroundColor, foregroundColor,
backgroundColor, foregroundColor)
end
end
end
end
local function ensureWindowOpened ()
if tableId = = nil then
return
end
if IsWindowClosed (tableId) then
CreateWindow (tableId)
SetWindowPos (tableId, 0 , 0 , 300 , 100 )
SetWindowCaption (tableId, "hang_test" )
InsertRow (tableId, 1 )
InsertRow (tableId, 2 )
SetCell (tableId, 1 , 1 , "11" )
SetCell (tableId, 1 , 2 , "12" )
SetCell (tableId, 2 , 1 , "21" )
SetCell (tableId, 2 , 2 , "22" )
SetSelectedRow (tableId, 1 )
end
setTableColors(foregroundColor, backgroundColor)
end
local function closeWindow ()
local t = tableId
tableId = nil
if t then
DestroyTable (t)
end
end
function OnInit (scriptPath)
tableId = AllocTable ()
AddColumn (tableId, 1 , "col1" , true , QTABLE_STRING_TYPE, 5 )
AddColumn (tableId, 2 , "col2" , true , QTABLE_STRING_TYPE, 5 )
SetTableNotificationCallback (tableId, function (tId, msg, par1, _)
if msg = = QTABLE_SELCHANGED then
SetSelectedRow (tId, 1 )
end
end )
ensureWindowOpened()
end
local function run ()
ensureWindowOpened()
if tableId then
SetSelectedRow (tableId, 2 )
end
end
function OnStop (flag)
pcall(closeWindow)
interrupted = true
end
function main ()
message ( "STARTED" , 1 )
while not interrupted do
run()
if flag then
sleep ( 0 )
end
end
pcall(closeWindow)
message ( "SHUTDOWN" , 1 )
end
причина зависания вероятнее всего в том, что функция main будет исполнена один раз до загрузки всех необходимых для корректной работы данных. Предположу, что это ошибка автора скрипта, так как в нем не учитывается многопоточность.
nikolz написал: Предположу, что это ошибка автора скрипта, так как в нем не учитывается многопоточность.
Филосов . Укажите конкретно в чем ошибка автора. --- Ошибки автора нет. Есть ошибка в QUIK, состоящая в том, что длинные участки фрагментов кода скрипта на "чистом Lua" (без вызова C-функций) блокируют переключение потоков обслуживающего колбеки и выполняющего main. Я не буду повторять свои комментарии по этому поводу. Читайте форум.
Если код функции OnStop модифицировать следующим образом:
Код
function OnStop (flag)
interrupted = true
message ( "OnStop executed" , 1 )
pcall(closeWindow)
end
то зависания не будет и, наверное, понятно почему.
Да, так и есть. Я пробовал этот вариант, но уже не стал писать в теме.
В общем, получается, что неплохо бы со стороны разработчиков обеспечить переключение между потоками даже в случае "длинного чистого Lua-кода". Я видел Ваши предложения по этому поводу, на которые разработчики, к сожалению, не реагируют.
Конечно, большинство программ пользователей имеют главный цикл со sleep внутри, так что совсем уж в явном виде проблема не стоит. Но переключение между потоками может сделать как работу терминала более отзывчивой, а также зависание, с которым я столкнулся, исключит.
nikolz написал: Предположу, что это ошибка автора скрипта, так как в нем не учитывается многопоточность.
Филосов :: . Укажите конкретно в чем ошибка автора. --- Ошибки автора нет. Есть ошибка в QUIK, состоящая в том, что длинные участки фрагментов кода скрипта на "чистом Lua" (без вызова C-функций) блокируют переключение потоков обслуживающего колбеки и выполняющего main. Я не буду повторять свои комментарии по этому поводу. Читайте форум.
ошибка автора в отсутствии знаний. И Ваша тоже так как Вы пишите про "чистый луа" который существует лишь в виде функций на чистом СИ. Это профанация и дилетанты вам верят.
читайте внимательно документацию прежде чем писать тесты. ---------------- Например, OnStop - Функция вызывается терминалом QUIK при остановке скрипта из диалога управления и при закрытии терминала QUIK.
Функция возвращает количество миллисекунд, которое дается скрипту на завершение работы.
Если функция не возвращает число, то таймаут завершения работы скрипта остается равным 5 секундам.
По истечении интервала времени, данного скрипту на завершение работы, функция main() завершается принудительно. При этом возможна потеря системных ресурсов.
=======================
Т е Вам дали время на завершение потока майн
Там и надо закрывать окна. А Вы делаете это в колбеке.
зачем закрывать окно и в колбеке и в main? ---------------------------- function OnStop(flag) pcall(closeWindow) interrupted = true end
function main() message("STARTED", 1) while not interrupted do run() if flag then sleep(0) end end pcall(closeWindow) message("SHUTDOWN", 1) end ====================
в колбеке в этой функции Вы уничтожаете окно ---------------------------- local function closeWindow() local t = tableId tableId = nil if t then DestroyTable(t) end end ------------------ А в main вы уничтожаете nil. Очевидно у Вас все вылетает по ошибке и вы вместо того чтобы правильно сделать ставите pcall ---------------- Т е не зная причину Вы блокируете сообщение об ошибке. полный дилетантизм.
_sk_ написал: Я видел Ваши предложения по этому поводу, на которые разработчики, к сожалению, не реагируют.
Для QLua 5.3 есть простое и эффективное решение, которое я протестировал. Но это решение не подходит к Qlua 5.4 так как там было существенно изменено управление памятью и с этим я разбираться не стал. Разработчик QUIK (через поддержку) заявил, что будет поддерживаться только QLua 5.4. Поэтому свои предложения я снял, опасаясь того, что их реализация разработчиком в QLua 5.4. может оказаться некорректной и последствия могут оказаться более неприятными чем то, что есть сейчас.
_sk_, вот Ваш тест с исправленными Вашими ошибками. Работает без проблем.
Код
local flag =false -- можно и false и true
local foregroundColor = RGB(0, 0, 0)
local backgroundColor = RGB(192, 255, 192)
local function setTableColors(foregroundColor, backgroundColor)
local nRows, nCols = GetTableSize(tableId)
if nRows and nCols then
for row = 1, nRows do
for col = 1, nCols do
SetColor(tableId, row, col,
backgroundColor, foregroundColor,
backgroundColor, foregroundColor)
end
end
end
end
local function ensureWindowOpened()
if tableId == nil then return end
if IsWindowClosed(tableId) then
CreateWindow(tableId)
SetWindowPos(tableId, 0, 0, 300, 100)
SetWindowCaption(tableId, "hang_test")
InsertRow(tableId, 1)
InsertRow(tableId, 2)
SetCell(tableId, 1, 1, "11")
SetCell(tableId, 1, 2, "12")
SetCell(tableId, 2, 1, "21")
SetCell(tableId, 2, 2, "22")
SetSelectedRow(tableId, 1)
end
setTableColors(foregroundColor, backgroundColor)
end
function OnInit(scriptPath)
tableId = AllocTable()
AddColumn(tableId, 1, "col1", true, QTABLE_STRING_TYPE, 5)
AddColumn(tableId, 2, "col2", true, QTABLE_STRING_TYPE, 5)
SetTableNotificationCallback(tableId, function(tId, msg, par1, _)
if msg == QTABLE_SELCHANGED then
SetSelectedRow(tId, 1)
end
end)
ensureWindowOpened()
end
local function run()
ensureWindowOpened()
if tableId then
SetSelectedRow(tableId, 2)
end
end
function OnStop(flag)
DestroyTable(tableId);
interrupted = true
end
function main()
message("STARTED", 1)
while not interrupted do
run()
if flag then
sleep(0)
end
end
message("SHUTDOWN", 1)
end
nikolz написал: _sk_ ,вот Ваш тест с исправленными Вашими ошибками. Работает без проблем.
Вы до сих пор не поняли, что у _sk_ нет проблем со скритом ( он делает flag = true и все у него хорошо ). Его интерисует странное поведение скрипта когда flag =false и это нормально. Вообще, из того что видно невооруженным взглядом, у вас постоянный зуд отметиться на форуме (как у собачки, выпущенной на прогулку ). Зачем вы работаете на форуме «прокладкой» между комментариями? Явно, что у вас проблемы с вашими комплексами и вы пытаетесь здесь их скомпенсировать. Но вы до сих пор не научились выделять фрагменты текстов комментариев, которые вы цитируете. Вас можно пожалеть (девочки точно не любят), но вы постоянно спамите на форуме и скоро переполните его базу . Меня это беспокоит и только поэтому я на вас реагирую .
попроще можно сказать что и main и OnStop исполняются (вызываются) под единым мьютексом. который снимается всего двумя способами а) выходом из функции б) обращением к С-function и sleep - это вариант б)
при б) мьютекс снимается на входе в С-функцию и возвращается при возвращении из неё. при этом если С-функция в свою очередь обратится в Lua, то мьютекс тоже будет выставлен на время такого обращения и снимется при возврате в С функцию отличие между Lua и С-функцией определяется через lua_iscfunction
в Quik Lua почти всё C-функции. поэтому sleep(0) можно заменить, например, tostring, да и pcall тоже С-функция, так что наверно в main сработало бы pcall(run) без флагов
Реализация Lua-машины такова, что перед входом в главный цикл интерпретатора объект синхронизации захватывается и отпускается только в некоторых случаях, например, при вызове внешних функций (в частности, sleep). Рекомендуем использовать вызов функции sleep() внутри цикла, чтобы исключить зависание приложения.
nikolz написал: _sk_ ,вот Ваш тест с исправленными Вашими ошибками. Работает без проблем.
Вы до сих пор не поняли, что у _sk_ нет проблем со скритом ( он делает flag = true и все у него хорошо ). Его интерисует странное поведение скрипта когда flag =false и это нормально. Вообще, из того что видно невооруженным взглядом, у вас постоянный зуд отметиться на форуме (как у собачки, выпущенной на прогулку :: ). Зачем вы работаете на форуме «прокладкой» между комментариями? Явно, что у вас проблемы с вашими комплексами и вы пытаетесь здесь их скомпенсировать. Но вы до сих пор не научились выделять фрагменты текстов комментариев, которые вы цитируете. Вас можно пожалеть (девочки точно не любят), но вы постоянно спамите на форуме и скоро переполните его базу :: . Меня это беспокоит и только поэтому я на вас реагирую :: .
Вы не поняли, я исправил у него ошибки и можете делать хоть faLSE
TGB, исправленный скрипт не виснет Вы вместо брызжания проверьте тест. ------------------- если есть другие проблемы , то пишите я исправлю. ---------------------- И очевидно, и у кого что болит тот о том и говорит
Реализация Lua-машины такова, что перед входом в главный цикл интерпретатора объект синхронизации захватывается и отпускается только в некоторых случаях, например, при вызове внешних функций (в частности, sleep). Рекомендуем использовать вызов функции sleep() внутри цикла, чтобы исключить зависание приложения.
Спасибо за пояснения о ттехподдержки. Хорошо, что они совпадают с теми, что высказали другие участники общения в этой теме.