El El (Все сообщения пользователя)

Выбрать дату в календареВыбрать дату в календаре

Страницы: 1 2 След.
Lua Dll на C++
 
lua_newthread создает Lua thread, которая не является thread (потоком) операционной системы. В документации, когда пишут, что main и OnXXX вызываются на разных потоках (thread), речь идет о настоящих потоках операционной системы.
Самый короткая и полезная формулировка на этот счет: https://stackoverflow.com/questions/17817452/lua-5-2-2-broken-threading-system/17818481#17818481
Возможно, стоит предложить добавить в документацию уточненения, о каких потоках идет речь, если они употребляют слово "поток".

Нет никаких гарантий, что lua_State* для OnXxx будет оставаться тем же, например разработчики, могут начать синхронизировать потоки каким-нибудь изысканным способом, который в итоге поменяет указатель на эту структуру. Поэтому безопаснее не кешировать эти указатели в своих объектах, тем более что это ничего не стоит. Более подробные соображения по этому поводу тут: https://github.com/elelel/qluacpp-tutorial/issues/5
Подвешивание info.exe через механизм межпоточного локинга
 
Цитата
Антон написал:

Вобщем все же уже есть (только в документации как всегда пусто).
Передаем в ssort таблицу на 2 элемента и заглушку которая вызывает пользовательский колбек. (интересно как сделать чтобы не передавать таблицу каждый раз?)
Почему бы не добавить функцию в qlua которая будет делаеть тоже самое но без заглушки?
res = scall( function, params...); 2 варианта (с ожиданием и без)
Полгода назад я предлагал сделать такой вызов, но результат, к сожалению, - "ваше предложение зарегистрировано".
Тем не менее, сейчас речь о том, что ряд функций QLua непотоконебезопасны даже в случае синхронизации относительно объекта, передаваемого в EnterCriticalSection внутри ssort. Мой скрипт выше воспроизводит такую ошибку.
Подвешивание info.exe через механизм межпоточного локинга
 
Цитата
Michael Bulychev написал:
Добрый день.
Может будет проще если Вы объясните какую задачу хотите решить?
Изначально моя задача - позволить пользователям моей библиотеки писать потокобезопасный код при написании QLua-плагинов к Quik. Эта задача лежит вне области поддержки с вашей стороны, и я на такую поддержку не претендую.
Решая эту задачу своими методами, я заметил, что при определенных обстоятельствах терминал подвешивается, но глубоко в эту сторону не копал и списывал причины именно на свои методы. Сейчас дошли руки заняться этим вопросом снова, и,
пытаясь найти ошибку в логике своего кода, я пришел к выводу, что проблема не в моем коде (я пробовал разные варианты синхронизации между потоком скрипта и основным потоком). Условия подвисания вырисовалось такое, как я описал выше: терминал подвиснет, если в потоке main произойдет вызов "плохой" функции типа InsertRow или Clear в случае, если на основном потоке не завершилось исполнение хендлера колбека юзерского кода. Вероятно, то же самое происходит если "плохая" функция будет вызвана в коллбеке на основном потоке до того, как завершил работу обработчик коллбека на этом же потоке (этот вариант я не подтвердил твердо экспериментально). Такие условия подвисания должны затрагивать не только меня, как пользователя, пытающегося воспользоваться не поддерживающимся функционалом. Эти подвисания должны случаться и у других пользователей, но, с учетом того, что все они в своем большинстве вставляют в main sleep на сотни миллисекунд и других особенностей типового Qlua скрипта, вероятность такого события просто очень низка. Исходя из этого, я написал скрипт чисто на Quik Lua с использованием строго поддерживающегося функционала, чтобы спровоцировать эту ситуацию с вероятностью достаточно высокой для заметного воспроизведения ошибки. К сожалению, чтоб управлять очередностью исполнения потоков при помощи только поддерживающегося функционала QLua, мне пришлось прибегнуть к "потокобезопасным функциям" (в терминах qlua.chm), используя их неочевидным образом для неочевидных целей, хотя и в соответствии с описанием. Из-за этого по коду может быть не с первого взгляда ясно, при какой ситуации происходит подвисание. Поэтому впоследствии я прокомментировал, что подвисание происходит при указанной очередности событий, хотя относительно нее вам придется поверить (или не поверить) мне на слово, поскольку саму эту очередность я выявил своими неподдерживающимися методами. Просто хотел облегчить вам задачу поиска. Таким образом, моя задача - предотвратить подвисания внутри функций типа Close, InsertRow и др. в обычных QLua скриптах при описанных мной обстоятельствах. Если эта задача будет решена, то с моей стороны это автоматически будет означать и решение моей проблемы потокобезопасных интерфейсов, которая официальной поддержке не подлежит.
Подвешивание info.exe через механизм межпоточного локинга
 
Исправление строк в тексте сообщений в OnQuote:
Код
tid = 0

events = {}
mp_counter = 0
qp_counter = 0

-- Predicates to be called from two threads
-- To hang Quik we will try to collide QLUA functions
-- Risk factors: we're using heavily CriticalSection (through ssort) and the events are fast enough

-- Predicate for script's dedicated thread
function script_predicate(a, b)
   print("SCRIPT: script_predicate entry")
   mp_counter = mp_counter + 1;
   if ((mp_counter % 7) == 0) then
      print("SCRIPT: Calling Clear")
      Clear(tid)
      print("SCRIPT: Returned from Clear")
   end
   print("SCRIPT: Calling SetWindowCaption")
   SetWindowCaption(tid, "Just called script thread predicate " .. mp_counter .. " times")
   print("SCRIPT: Returned from SetWindowCaption")
   print("SCRIPT: Calling InsertRow")
   local n = InsertRow(tid, -1)
   print("SCRIPT: Returned from InsertRow")
   print("SCRIPT: Calling SetCell")
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with script thread predicate", 0);
   print("SCRIPT: Returned from SetCell")
   print("SCRIPT: script_predicate end")
   return b > a
end

-- Predicate for Quik's main thread
function main_predicate(a, b)
   print("MAIN: main_predicate entry")
   qp_counter = qp_counter + 1;
   if ((qp_counter % 7) == 0) then
      print("MAIN: Calling Clear")
      Clear(tid)
      print("MAIN: Returned from Clear")
   end
   SetWindowCaption(tid, "Just called main thread predicate " .. cp_counter .. " times")
   print("MAIN: Returned from SetWindowCaption")
   print("MAIN: Calling InsertRow")
   local n = InsertRow(tid, -1)
   print("MAIN: Returned from InsertRow")
   print("MAIN: Calling SetCell")
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with main thread predicate", 0);
   print("MAIN: Returned from SetCell")
   print("MAIN: main_predicate end")
   return a < b
end

function main()
   -- Turn off buffering to stdout
   io.stdout:setvbuf("no")
   
   Subscribe_Level_II_Quotes("QJSIM", "LKOH");
   Subscribe_Level_II_Quotes("QJSIM", "SBER");
   Subscribe_Level_II_Quotes("QJSIM", "GMKN");
   Subscribe_Level_II_Quotes("QJSIM", "SBERP");
   Subscribe_Level_II_Quotes("QJSIM", "MGNT");
   Subscribe_Level_II_Quotes("QJSIM", "ROSN");
   Subscribe_Level_II_Quotes("QJSIM", "AFLT");
   Subscribe_Level_II_Quotes("QJSIM", "BANE");
   Subscribe_Level_II_Quotes("QJSIM", "MTLR");
   Subscribe_Level_II_Quotes("QJSIM", "BANEP");

   tid = AllocTable()
   AddColumn(tid, 1, "Event", true, QTABLE_STRING_TYPE, 80)
   CreateWindow(tid)
   local cycles = 0;
   while true do
      sleep(1)
      cycles = cycles + 1;
      if (cycles == 100) then
         print("SCRIPT: Calling ssort")
         table.ssort(events, script_predicate)
         print("SCRIPT: Returned from ssort")
         if (table.getn(events) > 0) then
            print("SCRIPT: Calling InsertRow")
            local n = InsertRow(tid, -1)
            print("SCRIPT: Returned from InsertRow")
            print("SCRIPT: Calling SetCell")
            SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
            print("SCRIPT: Returned from SetCell")
         end
         cycles = 0
      end
   end
end

function OnQuote(class_code, sec_code)
   print("MAIN: OnQuote entry")
   local q = getQuoteLevel2(class_code, sec_code)
   if ((q ~= nil) and (tonumber(q.bid_count) > 0)) then
      print("MAIN: Calling getn")
      if (table.getn(events) > 8) then events = {} end
      print("MAIN: Returned from getn")
      print("MAIN: Calling sinsert")
      table.sinsert(events, q.bid[1].price)
      print("MAIN: Returned from sinsert")
      print("MAIN: Calling ssort")
      table.ssort(events, quik_predicate)
      print("MAIN: Returned from ssort")
      if (table.getn(events) > 0) then
         print("MAIN: Calling InsertRow")
         local n = InsertRow(tid, -1)
         print("MAIN: Returned from InsertRow")
         print("MAIN: Calling SetCell")
         SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
         print("MAIN: Returned from SetCell")
      end
   end
   print("MAIN: OnQuote end")
end

Подвешивание info.exe через механизм межпоточного локинга
 
Чтобы было проще, я написал логирование каждого вызова к Qlua функции. Логинг в stdout, т.к. в такой ситуации на дебаг стринги через сам Qlua, который пытаемся дебагить, полагаться нельзя, поэтому чтоб получить лог, нужно фронт пускать через терминал или с перенаправлением stdout: info.exe > log.txt
Этот вариант у меня подвисает минуты через 2 после старта.

Тестовый скрипт:
Код
tid = 0

events = {}
mp_counter = 0
qp_counter = 0

-- Predicates to be called from two threads
-- To hang Quik we will try to collide QLUA functions
-- Risk factors: we're using heavily CriticalSection (through ssort) and the events are fast enough

-- Predicate for script's dedicated thread
function script_predicate(a, b)
   print("SCRIPT: script_predicate entry")
   mp_counter = mp_counter + 1;
   if ((mp_counter % 7) == 0) then
      print("SCRIPT: Calling Clear")
      Clear(tid)
      print("SCRIPT: Returned from Clear")
   end
   print("SCRIPT: Calling SetWindowCaption")
   SetWindowCaption(tid, "Just called script thread predicate " .. mp_counter .. " times")
   print("SCRIPT: Returned from SetWindowCaption")
   print("SCRIPT: Calling InsertRow")
   local n = InsertRow(tid, -1)
   print("SCRIPT: Returned from InsertRow")
   print("SCRIPT: Calling SetCell")
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with script thread predicate", 0);
   print("SCRIPT: Returned from SetCell")
   print("SCRIPT: script_predicate end")
   return b > a
end

-- Predicate for Quik's main thread
function main_predicate(a, b)
   print("MAIN: main_predicate entry")
   qp_counter = qp_counter + 1;
   if ((qp_counter % 7) == 0) then
      print("MAIN: Calling Clear")
      Clear(tid)
      print("MAIN: Returned from Clear")
   end
   SetWindowCaption(tid, "Just called main thread predicate " .. cp_counter .. " times")
   print("MAIN: Returned from SetWindowCaption")
   print("MAIN: Calling InsertRow")
   local n = InsertRow(tid, -1)
   print("MAIN: Returned from InsertRow")
   print("MAIN: Calling SetCell")
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with main thread predicate", 0);
   print("MAIN: Returned from SetCell")
   print("MAIN: main_predicate end")
   return a < b
end

function main()
   -- Turn off buffering to stdout
   io.stdout:setvbuf("no")
   
   Subscribe_Level_II_Quotes("QJSIM", "LKOH");
   Subscribe_Level_II_Quotes("QJSIM", "SBER");
   Subscribe_Level_II_Quotes("QJSIM", "GMKN");
   Subscribe_Level_II_Quotes("QJSIM", "SBERP");
   Subscribe_Level_II_Quotes("QJSIM", "MGNT");
   Subscribe_Level_II_Quotes("QJSIM", "ROSN");
   Subscribe_Level_II_Quotes("QJSIM", "AFLT");
   Subscribe_Level_II_Quotes("QJSIM", "BANE");
   Subscribe_Level_II_Quotes("QJSIM", "MTLR");
   Subscribe_Level_II_Quotes("QJSIM", "BANEP");

   tid = AllocTable()
   AddColumn(tid, 1, "Event", true, QTABLE_STRING_TYPE, 80)
   CreateWindow(tid)
   local cycles = 0;
   while true do
      sleep(1)
      cycles = cycles + 1;
      if (cycles == 100) then
         print("SCRIPT: Calling ssort")
         table.ssort(events, script_predicate)
         print("SCRIPT: Returned from ssort")
         if (table.getn(events) > 0) then
            print("SCRIPT: Calling InsertRow")
            local n = InsertRow(tid, -1)
            print("SCRIPT: Returned from InsertRow")
            print("SCRIPT: Calling SetCell")
            SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
            print("SCRIPT: Returned from SetCell")
         end
         cycles = 0
      end
   end
end

function OnQuote(class_code, sec_code)
   print("MAIN: OnQuote entry")
   local q = getQuoteLevel2(class_code, sec_code)
   if ((q ~= nil) and (tonumber(q.bid_count) > 0)) then
      print("SCRIPT: Calling getn")
      if (table.getn(events) > 8) then events = {} end
      print("SCRIPT: Returned from getn")
      print("SCRIPT: Calling sinsert")
      table.sinsert(events, q.bid[1].price)
      print("SCRIPT: Returned from sinsert")
      print("SCRIPT: Calling ssort")
      table.ssort(events, quik_predicate)
      print("SCRIPT: Returned from ssort")
      if (table.getn(events) > 0) then
         print("SCRIPT: Calling InsertRow")
         local n = InsertRow(tid, -1)
         print("SCRIPT: Returned from InsertRow")
         print("SCRIPT: Calling SetCell")
         SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
         print("SCRIPT: Returned from SetCell")
      end
   end
   print("MAIN: OnQuote end")
end

В момент подвисания у меня может быть, например, такой лог:
Код
...
SCRIPT: Calling SetCell
SCRIPT: Returned from SetCell
SCRIPT: script_predicate end
SCRIPT: script_predicate entry
SCRIPT: Calling Clear
SCRIPT: Returned from Clear
SCRIPT: Calling SetWindowCaption
SCRIPT: Returned from SetWindowCaption
SCRIPT: Calling InsertRow



Обратите внимание, что подвисает на InsertRow, когда мы заведомо находимся внутри своей критической секции (внутри предиката к ssort), то есть подвисает не потому, что мы ждем, пока нам передадут управление в рамках занятой кем-то еще критической сессии, используемой в ssort. Подвисания происходят всегда внутри "плохих" функций.
Подвешивание info.exe через механизм межпоточного локинга
 
Вообще, условие возникновение проблемы гораздо более простое, чем в скрипте. Нужно, чтобы начал исполняться обработчик (любой: OnQuote, OnTrade), но до того как он закончил исполнение, проснулся бы другой тред и вызвал бы "плохую функцию", например Clear. Если "плохая" функция начнет исполнение до того, как закончит исполнение пользовательский обработчик, это достаточное условие чтоб оно подвисло. Совсем не нужно мучать ssort и прочее. Просто это sleep и ssort-подбные функции - единственные, чем можно управлять в Qlua потоками. А мне нужно было что-то, чем управлять потоками, чтоб в соответствии с "регламентом" обратиться на форуме и привести пример проблемы со скриптом на Lua. Я не мог сказать "усыпляйте мейн тред скрипта, а в конце любого обработчика пробуждайте, так, чтоб сразу вызвался Clear в мейне скрипта". Но изначально с проблемой я столкнулся сделав именно это.
Подвешивание info.exe через механизм межпоточного локинга
 
Цитата
Michael Bulychev написал:
Добрый день.
Эксперимернты показали, что взаимных блокировок (deadlock) при работе скрипта не происходит. Просто основной поток фронта очень загружен и  не откликается на действия пользователей. Потокобезопаные функции библиотеки table устроены так, что на время выполнения полностью блокируют все остальные потоки для данной виртуальной машины Lua. Учитывая что таблица events в Вашем примере постоянно растет, то и время работы функций sinsert и ssort все время увеличивается.
У меня подвисает даже если поддерживать таблицу events размером не более 2 элемента в OnQuote


Модифицированный скрипт:
Код
tid = 0

events = {}
mp_counter = 0
qp_counter = 0

-- Predicates to be called from two threads
-- To hang Quik we will try to collide QLUA functions
-- Risk factors: we're using heavily CriticalSection (through ssort) and the events are fast enough

-- Predicate for script's dedicated thread
function main_predicate(a, b)
   mp_counter = mp_counter + 1;
   if ((mp_counter % 7) == 0) then Clear(tid) end
   SetWindowCaption(tid, "Just called script thread predicate " .. mp_counter .. " times")
   local n = InsertRow(tid, -1)
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with script thread predicate", 0);
   return b > a
end

-- Predicate for Quik's main thread
function quik_predicate(a, b)
   qp_counter = qp_counter + 1;
   if ((qp_counter % 13) == 0) then Clear(tid) end
   local n = InsertRow(tid, -1)
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with main thread predicate", 0);
   SetWindowCaption(tid, "Just called quik thread predicate " .. qp_counter .. " times")
   return a < b
end

function main()
   Subscribe_Level_II_Quotes("QJSIM", "LKOH");
   Subscribe_Level_II_Quotes("QJSIM", "SBER");
   Subscribe_Level_II_Quotes("QJSIM", "GMKN");
   Subscribe_Level_II_Quotes("QJSIM", "SBERP");
   Subscribe_Level_II_Quotes("QJSIM", "MGNT");
   Subscribe_Level_II_Quotes("QJSIM", "ROSN");
   Subscribe_Level_II_Quotes("QJSIM", "AFLT");
   Subscribe_Level_II_Quotes("QJSIM", "BANE");
   Subscribe_Level_II_Quotes("QJSIM", "MTLR");
   Subscribe_Level_II_Quotes("QJSIM", "BANEP");

   tid = AllocTable()
   AddColumn(tid, 1, "Event", true, QTABLE_STRING_TYPE, 80)
   CreateWindow(tid)
   local cycles = 0;
   while true do
      sleep(1)
      cycles = cycles + 1;
      if (cycles == 100) then
         table.ssort(events, main_predicate)
         if (table.getn(events) > 0) then
            local n = InsertRow(tid, -1)
            SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
         end
         cycles = 0
      end
   end
end

function OnQuote(class_code, sec_code)
   local q = getQuoteLevel2(class_code, sec_code)
   if ((q ~= nil) and (tonumber(q.bid_count) > 0)) then
      if (table.getn(events) > 2) then events = {} end
      table.sinsert(events, q.bid[1].price)
      table.ssort(events, quik_predicate)
      if (table.getn(events) > 0) then
         local n = InsertRow(tid, -1)
         SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
      end
   end
end

Nil в полях таблицы classes
 
Цитата
Stanislav Tvorogov написал:
Добрый день,
Цитата
El El   написал:
Qlua.chm, Структуры данных - Классы
Я исходил из того, что если поле может содержать nil, то в описание указывается "параметр может иметь значение nil", как в других описаниях структур данных (например "Транзакции")
Вероятно, Вами имелось ввиду то, что сама функция getItem возвращает nil. В файле действительно это не указано.
Ваше сообщение получено, проблема изучается. Постараемся в ближайшее время дать ответ.
Функцией getItem возвращаются корректные (не nil) записи по getItem, проверку самой записи на не-nil проходят, но эти три поля внутри записи бывают nil. Получено путем попытки запроса каждого поля всех записей всех таблиц, указанных в разделе "таблицы, используемые с getItem" для проверок корректности типа данных (часто в документации STRING/NUMBER не соответствуют). Проверка была на старте Quik Junior сразу после коннекта в дефолтной конфигурации по запросу терминалом параметров и т.п. В ближайшее время напишу тест конкретно под эти nil на Lua.
Nil в полях таблицы classes
 
Цитата
Stanislav Tvorogov написал:
Добрый день,
Цитата
El El   написал:
При вызове getItem для получения записей таблицы classes поля class_code, npars, nsecs могут содержать nil, что противоречит описанию.
Уточните, о каком именно описании идет речь? По возможности сообщите пожалуйста позицию в "содержании" файла QLUA.chm.
Qlua.chm, Структуры данных - Классы
Я исходил из того, что если поле может содержать nil, то в описание указывается "параметр может иметь значение nil", как в других описаниях структур данных (например "Транзакции")
Nil в полях таблицы classes
 
При вызове getItem для получения записей таблицы classes поля class_code, npars, nsecs могут содержать nil, что противоречит описанию. В описании таблицы "Классы" поле называется class_code, в примере этой же страницы - class.
Подвешивание info.exe через механизм межпоточного локинга
 
Дополнительно: оно иногда отвисает, если подождать минут 10 после повисания, после чего UI Квика нормален, но скрипт как будто останавливается. В статусе по иконке в списке скриптов тем не менее - продолжение исполнения (зеленая стрелочка).
Подвешивание info.exe через механизм межпоточного локинга
 
Цитата
El El,  В заголовке times уже +30000 пока полет нормальный. А у Вас при каком значении зависает терминал?
По-разному, попробуйте попосылать ему UI события (покликать на окно мышкой, подвигать окно), подвиснет гораздо быстрее, иногда сразу.
Подвешивание info.exe через механизм межпоточного локинга
 
Заметил, что не сбрасываю счетчик cycles, соответственно видимо тут столкновения происходят между вызовами на основном потоке Quik
Подвешивание info.exe через механизм межпоточного локинга
 
Исправление форматирования:
Код
tid = 0

events = {}
mp_counter = 0
qp_counter = 0

-- Predicates to be called from two threads
-- To hang Quik we will try to collide QLUA functions
-- Risk factors: we're using heavily CriticalSection (through ssort) and the events are fast enough

-- Predicate for script's dedicated thread
function main_predicate(a, b)
   mp_counter = mp_counter + 1;
   if ((mp_counter % 7) == 0) then Clear(tid) end
   SetWindowCaption(tid, "Just called script thread predicate " .. mp_counter .. " times")
   local n = InsertRow(tid, -1)
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with script thread predicate", 0);
   return b > a
end

-- Predicate for Quik's main thread
function quik_predicate(a, b)
   qp_counter = qp_counter + 1;
   if ((qp_counter % 13) == 0) then Clear(tid) end
   local n = InsertRow(tid, -1)
   SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with main thread predicate", 0);
   SetWindowCaption(tid, "Just called quik thread predicate " .. qp_counter .. " times")
   return a < b
end

function main()
   Subscribe_Level_II_Quotes("QJSIM", "LKOH");
   Subscribe_Level_II_Quotes("QJSIM", "SBER");
   Subscribe_Level_II_Quotes("QJSIM", "GMKN");
   Subscribe_Level_II_Quotes("QJSIM", "SBERP");
   Subscribe_Level_II_Quotes("QJSIM", "MGNT");
   Subscribe_Level_II_Quotes("QJSIM", "ROSN");
   Subscribe_Level_II_Quotes("QJSIM", "AFLT");
   Subscribe_Level_II_Quotes("QJSIM", "BANE");
   Subscribe_Level_II_Quotes("QJSIM", "MTLR");
   Subscribe_Level_II_Quotes("QJSIM", "BANEP");

   tid = AllocTable()
   AddColumn(tid, 1, "Event", true, QTABLE_STRING_TYPE, 80)
   CreateWindow(tid)
   local cycles = 0;
   while true do
      sleep(1)
      cycles = cycles + 1;
      if (cycles == 100) then
         table.ssort(events, main_predicate)
         if (table.getn(events) > 0) then
            local n = InsertRow(tid, -1)
            SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
         end
      end
   end
end

function OnQuote(class_code, sec_code)
   local q = getQuoteLevel2(class_code, sec_code)
   if ((q ~= nil) and (tonumber(q.bid_count) > 0)) then
      table.sinsert(events, q.bid[1].price)
      table.ssort(events, quik_predicate)
      if (table.getn(events) > 0) then
         local n = InsertRow(tid, -1)
         SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
      end
   end
end


Подвешивание info.exe через механизм межпоточного локинга
 
Цитата
tid = 0

events = {}
mp_counter = 0
qp_counter = 0

-- Predicates to be called from two threads
-- To hang Quik we will try to collide QLUA functions
-- Risk factors: we're using heavily CriticalSection (through ssort) and the events are fast enough

-- Predicate for script's dedicated thread
function main_predicate(a, b)
  mp_counter = mp_counter + 1;
  if ((mp_counter % 7) == 0) then Clear(tid) end
  SetWindowCaption(tid, "Just called script thread predicate " .. mp_counter .. " times")
  local n = InsertRow(tid, -1)
  SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with script thread predicate", 0);
  return b > a
end

-- Predicate for Quik's main thread
function quik_predicate(a, b)
  qp_counter = qp_counter + 1;
  if ((qp_counter % 13) == 0) then Clear(tid) end
  local n = InsertRow(tid, -1)
  SetCell(tid, n, 1, "Compared " .. a .. " and " .. b .. " with main thread predicate", 0);
  SetWindowCaption(tid, "Just called quik thread predicate " .. qp_counter .. " times")
  return a < b
end

function main()
  Subscribe_Level_II_Quotes("QJSIM", "LKOH");
  Subscribe_Level_II_Quotes("QJSIM", "SBER");
  Subscribe_Level_II_Quotes("QJSIM", "GMKN");
  Subscribe_Level_II_Quotes("QJSIM", "SBERP");
  Subscribe_Level_II_Quotes("QJSIM", "MGNT");
  Subscribe_Level_II_Quotes("QJSIM", "ROSN");
  Subscribe_Level_II_Quotes("QJSIM", "AFLT");
  Subscribe_Level_II_Quotes("QJSIM", "BANE");
  Subscribe_Level_II_Quotes("QJSIM", "MTLR");
  Subscribe_Level_II_Quotes("QJSIM", "BANEP");

  tid = AllocTable()
  AddColumn(tid, 1, "Event", true, QTABLE_STRING_TYPE, 80)
  CreateWindow(tid)
  local cycles = 0;
  while true do
     sleep(1)
     cycles = cycles + 1;
     if (cycles == 100) then
        table.ssort(events, main_predicate)
        if (table.getn(events) > 0) then
           local n = InsertRow(tid, -1)
           SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
        end
     end
  end
end

function OnQuote(class_code, sec_code)
  local q = getQuoteLevel2(class_code, sec_code)
  if ((q ~= nil) and (tonumber(q.bid_count) > 0)) then
     table.sinsert(events, q.bid[1].price)
     table.ssort(events, quik_predicate)
     if (table.getn(events) > 0) then
        local n = InsertRow(tid, -1)
        SetCell(tid, n, 1, "First item after sorting in main is: " .. events[1], 0)
     end
  end
end
В течение первой пары минут работы скрипт подвесит терминал. Придумывалось, как тестовый скрипт для иллюстрации этой проблемы (https://forum.quik.ru/forum10/topic3206/) на чистом Lua, но может быть связан и просто со слишком частым main.
ssort не проверяет первый аргумент и вешает терминал
 
Функция table.ssort (в отличие от родного sort) не проверяет первый аргумент. Если его не задать вообще, вешает терминал. Привожу пример скрипта :)
Цитата
function main
 table.ssort()
end
Синхронизация между потоком main и потоком, вызывающим OnXxx
 
Цитата
Когда ещё был старый форум, там это обсуждалось. Пусть кто-нибудь из представителей ARQA дальше по теме видимости изменения переменных отвечает (даёт ссылку на соответствующее обсуждение или заново тут ответит).

Приведённый мною код работает с конца 2013 года без каких-либо проблем.
Если то, что я предполагаю, верно, то даже в этом случае встретить ошибку шанс минимален. По сути, это классическая ситуация с многопоточностью в нативном приложении, когда есть два потока и одна переменная, допустим int, и даже если известно, что один поток только пишет, а второй только читает, можно обойтись без локинга, если есть гарантия, что операции чтения и записи - атомарны. То, есть на C++ формально нельзя делать так, хотя в реальной жизни наткнуться на последствия проблемы очень маловероятно:
Цитата
int x;

thread1_proc() {
 while (...) {
    if (x == 1) {
      ...
    }
 }
}

thread2_proc() {
 while (...) {
   if (...) {
     x = 1;
   } else {
     x = ...
   }
 }
}
Но можно делать, если x будет объявлен как std::atomic<int> x; потому что иначе простая строчка типа x = 1 или x == 1 компилируются в много инструкций, которые могут быть перемешаны, например, с частью инструкций от следующей строки С++ кода.
Поэтому действительно хочется услышать кого-нибудь из разработчиков, действительно они каким-то образом гарантируют атомарность присвоения и чтения всех переменных Lua. Задача эта, как мне кажется, нетривиальная.

Цитата
Конечно, так и надо делать. Только в стандартном Lua для этого нет средств, а в QLua, наверное, через sinsert как-то можно извратиться и реализовать Lock. На практике же повелось так, что в main-потоке большинство пишет цикл, совершающий нужные проверки/действия и засыпающий, если это надо/есть возможность.
Все упирается в то, что в Lua в принципе нет исполнения одного контекста на разных реальных (таких, как тут) потоках. Не то что для этого нет средств, она в принципе не предназначена для того, чтоб с ней делали то, что сделано в Quik. Но нам даже из Lua можно сделать ровно то, что сделали разработчики Quik - использовать родные вызовы (например к WinApi) для работы с настоящими потоками. С их помощью можно сделать паузу в main (на что мы имеем право по документации) и уведомление о продолжении из колбеков. Единственное препятствие для такой схемы - то что некоторые вызовы, типа работы над табличным юзеринтерфейсом, блокирующие, в зависимости от ответа второго треда. Насчет этого требуется пояснения разработчиков, пока что приходится опытным путем устанавливать, какая у них логика локинга.
Синхронизация между потоком main и потоком, вызывающим OnXxx
 
Цитата
submit меняет только tail, get меняет только head. И указатели двигаются только в те моменты, когда структура готова. За видимость переменных из разных потоков разработчики QLua уже подумали

Операция присвоения не атомарна. В документации среди потокобезопасных функций она или аналоги не перечислена. То есть, по документации, можно быть уверенным что в середине
sinsert(...) не случится параллельного вызова, который обращается к той же структуре данных. А вот в середине self[self.tail + 1] = f он вполне можент случиться. По крайней мере я нигде
не нашел признаков того, что они на каждое присвоение производят синхронизацию между тредами. Это было бы убийственно для производительности, представляете, везде где встречается = нужно было
бы брать лок, делать операцию, снимать лок. По этой же причине, кстати, insert не сделан потокобезопасным, иначе бы на каждый его вызов приходилось бы все это дело блокировать/разблокировать, вместо
этого сделали безопасный sinsert, который бы пользователь вызывал только когда он действительно нужен.
Цитата
Передавайте только те данные, которые нужны. Полагаю, что если использовать что-то блокирующее, у Вас производительность понизится.
Производительность понижается в результате отсутствия блокировки. Потому что тогда приходится делать поллинг общей переменной - флага или очереди, как у вас. То есть, ее нужно в цикле внутри main опрашивать.
Если она опрашивается в цикле, то там будет блокировка, та же самая, только по таймеру (через функцию sleep). Моя блокировка отличается от такой блокировке только тем, что разблокировка происходит
по уведомлению из другого треда напрямую непосредственно в момент, когда нужно произвести действия.
Синхронизация между потоком main и потоком, вызывающим OnXxx
 
Здравствуйте, спасибо за ответ.

В коде выше чтение и запись в submit/get не синхронизированы. Что случится, если вызов будет произведен одновременно на двух родных потоках (мейн и колбек)?
Например, колбек вызовет submit, который уже модифицирует очередь при присвеоении, но еще не завершит операцию, а get уже начнет из нее читать?
В Lua скрипте такую схему можно было бы корректно реализовать при помощи функций, описанных в разделе "Потокобезопасные функции для работы с таблицами Lua" в qlua.chm.
На C++ подобную схему я делаю проще, с заведомо потокобезопасной структурой данных для очереди (как например тут https://github.com/elelel/qluacpp-tutorial/tree/master/log_all_trades ).
Все же, хотелось бы избежать копирования всего и вся из коллбеков в очередь. Если обработку производить в main, нужно будет саспендить этот поток (единственный
не созданный нами поток, который мы имеем право саспендить) и пробуждать по мере надобности. Но для этого надо знать условия, когда его можно саспендить, чтоб не
происходило блокировки обоих ниток по сценарию как оригинальном посте.
Синхронизация между потоком main и потоком, вызывающим OnXxx
 
Quik исполняет Lua скрипт на двух потоках. То, что внутри скриптовой функции main, исполняется на выделенном треде. Коллбеки OnXxxx исполняются на основном потоке Quik. Задача - гарантировать правильность последовательности вычислений, которые происходят внутри main и коллбеков. То есть, чтоб когда случился, например OnQuote, была бы гарантия, что исполняющийся параллельно main закончил свою часть вычислений и общие данные были бы в готовом состоянии. Примерный скрипт такой:
Код
data = {};

function update_ui()
   Clear(table_id)
   for i,v = in ipairs(data) do
      InsertRow(table_id, ...)
   end
end

function calculate_data_item(v)
   -- Calculate new value based on v
   -- Long, thread unsafe operation in real code, depends on other data[..] items
   -- Adding 1 here only as example
   return v + 1;
end

function update_all_data_items()
   for i,v = in ipairs(data) do
      data[i] = calculate_data_item(v);
   end
end

function main()
   -- Request level 2 quotes for each security
   -- Init table, columns ... 
   while true do
      -- START atomic operation on data array
      update_all_data_items()
      update_ui()
      -- End atomic operation
      sleep(1000)   
   end
end

function OnQuote(p1, p2)
   -- START atomic operation on data[p2]
   data[p2] = calculate_data_item(...)
   update_ui()
   -- End atomic operation on data[p2]
end

Там где в коментарии START - должна начинаться часть эксклюзивного кода, там где End - заканчиваться. Если организовать ожидание одним потоком пока завершит вычисления другой, то удается добиться полной корректности. Однако, некоторые функции Qlua (по всей видимости связанные с UI) блокируют исполнение, пока им не ответит основной тред Quik. В примере вызывается InsertRow и он внутри реализован так, что будет блокировать исполнение, пока ему не ответит основной тред Quik.

Происходит следующее:
1. main в точке START эксклюзивно запирает исполнение
2. Случается OnQuote и блокирует ожиданием основной поток Quik, пока исполнение заперто
3. В то же время main продолжает испололнение, благополучно завершает вычисление данных, подходит к вызову InsertRow
4. Внутри InsertRow происходит нечто, блокирующе зависящее от основного потока Quik
5. Основной поток Quik не откликается, потому что он в пункте 2 и ждет пока замок будет разлочен в main
6. main не может дойти до точки End, где замок разлочивается, потому что он ждет, пока InsertRow вернет исполнение

Получается, что внутри синхронизированного кода нельзя использовать ряд Qlua функций.
Вопросы:
1. Почему так происходит: InsertRow и подобные используют блокирующую отправку сообщений Windows (типа SendMessage вместо PostMessage) или это из-за логики локинга Quik? Понимание причины помогло бы придумать обходную схему
2. Какие функции поименно обладают таким же поведением как InsertRow? Понимание этого помогло бы писать скрипты так, чтоб хотя бы просто не натыкаться на эту проблему (не использовать внутри синхронизированного кода)
Когда Unsubscribe_Level_II_Quotes(...) == false?
 
В каких технических случаях Unsubscribe_Level_II_Quotes(...) возвращает false, если вызван после заведомо IsSubscribed_level_II_Quotes(...) == true?
DataSource.Close()
 
Код
function ds_callback(candle_idx)
   
end

function main()
   ds = CreateDataSource("TQBR", "SBER", INTERVAL_M1)
   if (ds == nil) then
      message("CreateDataSource returned nil")
   else
      r = ds:SetUpdateCallback(ds_callback)
      if (r == nil) then
         message("SetUpdateCallback returned nil")
      else
         if (r == false) then
            message("SetUpdateCallback returned false")
         end
      end
         
      while true do
         sleep(1000)
      end
   end
end

function OnStop(s)
   r = ds:SetEmptyCallback()
   if (r == nil) then
      message("SetEmptyCallback returned nil")
   else
      if (r == false) then
         message("SetEmptyCallback returned false")
      else
         r = ds:Close()
         if (r == nil) then
            message("Close returned nil")
         else
            if (r == false) then
               message("Close returned false")
            end
         end
      end
   end
end


Скрипт для тестирования в переводе на Lua. В OnStop Close() вернет nil.
DataSource.Close()
 
По документации метод Close() возвращает значение типа BOOLEAN. У меня после вызова Close на стеке лежит nil, это ошибка у меня или в документации?
Помогите принять Lua-таблицу в dll на c++
 
...или здесь, как просили, на C++ : https://github.com/elelel/qluacpp-tutorial/tree/master/l2q_wa

Но за два года человек наверняка уже получил свой стакан :)
Английский (US Engish), русский и пр. востребованные языки в одной программе
 
Цитата
A.T. написал:

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

Только, пожалуйста, не путайте британский и американский английский, что насколько я видел имеет место на данный момент. Это относится, например, к терминологии Bid/Ask (а не Offer). Я понимаю, что московская биржа создавалась в 1992 году по британскому образу и подобию, да и сегодня имеет близость именно с лондонской биржей из-за очень близкого совпадения торговых часов и торгуемых бумаг, но всё-таки мировые стандарты, практики и традиции являются именно американскими.

Спасибо, что выслушали.

В Quik и по-русски-то трудно понять, что имеется в виду (все, что можно - "котировки" и "параметры" и т.п.), а английский там - перевод с этого самого русского по мере сил (еще больше, чем то что можно - quotes). А уж до пожеланий британского и американского тут как до луны, если это, конечно, не шутка с вашей стороны была. Считайте, что вам повезло, что в вашем варианте английский язык не доступен, сохраняет психологическое здоровье.
LUA C++
 
Цитата
mmonk1980 написал:
Когда появиться реализация CreateDataSource, SetUpdateCallback, Size, Close, SetEmptyCallback? Просто библиотека месяц не исправлялась.
Написал специально для вас.
Также, предвосхищая вопросы "как пользоваться" - пример https://github.com/elelel/qluacpp-tutorial/tree/master/draw_candles_rt

Робот читает интернет-страницу
 
Цитата

Кроме того, пример содержит еще две особенности.
1) Скорректированная библиотека, т е недокументированная поделка.


2) Как сказано в примере: "Преобразование данных из HTML будет осуществляться для простоты "ручным" поиском строк и регулярными выражениями. В более серьезной архитектуре может применен XML-парсер и др., такой вариант оставляется читателю ручной способ поиска."
-----------------------------
Следовательно, это скорее всего - готовое частное решение, а не пример для подражания.
---------------------------------------
Полагаю, что более универсальное решение , может быть на luacom и InternetExplorer.Application.
Т е решении исключительно в рамках стандартов Майкрософт  и языка луа.
-------------------------------
Цитата
1) Скорректированная библиотека, т е недокументированная поделка.

Это по какой логике? Скорректированные библиотеки - недокументированные поделки? Причем тут документация (кроме того, это документировано на curl и там, откуда вы это списали)?
Цитата

2) Как сказано в примере: "Преобразование данных из HTML будет  осуществляться для простоты "ручным" поиском строк и регулярными  выражениями. В более серьезной архитектуре может применен XML-парсер и  др., такой вариант оставляется читателю ручной способ поиска."
-----------------------------
Следовательно, это скорее всего - готовое частное решение, а не пример для подражания.
А это по какой логике? Готовое частное решение по чтению частной страницы smartlab.
Робот читает интернет-страницу
 
Цитата
Николай Камынин написал:
Let_it_go ,
Ваша задача немного сложнее, чем пример который я написал.
Дело в том,страница, которую вы хотите читать не содержит готовой таблицы.
Поэтому кроме парсера Вам придется исполнять джава скрипты.
-------------------
Поэтому более правильно решать вашу задачу через использование браузера в качестве ком объекта.

Эта страница - статический html. Пример выше именно ее и достает и парсит. По крайней мере, так было месяц назад, когда пример писался.
Робот читает интернет-страницу
 
Практически такой робот есть в примерах Qluacpp: https://github.com/elelel/qluacpp-tutorial/tree/master/dividend_threat
Оно на C++, но может быть, будет полезно.
LUA C++
 
Цитата
mmonk1980 написал:
Вы хотели переписать библиотеку, прошел месяц - оно переписано или нет?
Да, ничего старого не осталось
LUA C++
 
Цитата
mmonk1980 написал:
my_main вызывается и все нормально, а вот OnAllTrade и OnQuote молчит, нечего не приходит! Может QUIK в квик надо поставит и еще что?
Пример по OnAllTrade добавлен сюда https://github.com/elelel/qluacpp-tutorial/
Цитата
mmonk1980 написал:
Как например вызвать CreateDataSource и CALLBACK к нему?
CreateDataSource не реализовывалась.
Цитата
mmonk1980 написал:
Написал

auto it = q.getItem<>("all_trades", 0);

выдает такую ошибку:

'qlua::api::getItem': no matching overloaded function found
'item_t qlua::api::getItem(const char *,const int) const': could not deduce template argument for 'item_t'

видимо функция не реализована.
Все реализовано, у вас неправильный стейтмент с точки зрения С++
Цитата
mmonk1980 написал:
Можно сделать как вот с этим?

par = q.getParamEx("SPBFUT", "MMM7", "BID");

вот так:

auto it = q.getItem("all_trades", 0, "BID");
Возможно, сделать так можно, но я так никогда не делал, потому что это имеет мало смысла. Вопрос, можно ли так делать, общий для QLUA и не относится к qluacpp, ответ следует искать на форуме Lua в других топиках или задавать отдельно, если он не задан. Если нужны данные, которые впоследствии оказываются в таблице all_trades, их надо получать по OnAllTrades. Если зачем-то нужна информация, как они представлены в этой таблице, например соотносить с привязкой к номеру ряда, то, наверное, можно делать как у вас.
LUA C++
 
Цитата
mmonk1980 написал:
my_main вызывается и все нормально, а вот OnAllTrade и OnQuote молчит, нечего не приходит! Может QUIK в квик надо поставит и еще что?
Моя догадка: если вы раскоментируете строку, в которой пользователю сообщается, когда скрипт завершил работу, скорей всего увидите, что вы ждете вызовов, когда скрипт уже не работает. Если main уже не работает, то и весь скрипт не работает, см. родную документацию QLUA. А может, дело в другом. Лучше подробно описать, чего вы хотите добиться от плагина.
LUA C++
 
Кроме того, и 3 секунды работы - у вас закоментированы.
LUA C++
 
Вы уверены, что у вас OnQuote случается в первые 3 секунды после запуска скрипта?
LUA C++
 
Цитата
mmonk1980 написал:
Цитата
El El   написал:
Если нужно, как вы писали выше, подключить библиотеку уже к существующему не-CMake проекту в студии, нужно сделать то же самое, но скачав только qluacpp, и указав дополнительно всего-лишь две опции: путь к .h файлу от lua и путь к .lib файлу от lua.
Такое делал не помогает.
"Не помогает" - как конкретно? Что конкретно делали и какие именно ошибки? Лучше открыть issue на github, чтоб не напрягать читателей этого форума лишней информацией.
LUA C++
 
Цитата
mmonk1980 написал:
Программисты разные бывают я например не cmake не пользуюсь и сразу ступор встаю как это делать. Обычно .sln идет c либой и example можно сразу проверить.
Я тут к сожалению не смогу помочь, последние лет 10 я Студией пользуюсь только через CMake, причем как правило только тулзами командоной строки от нее, в основном для проверки собираемости проектов на разных компиляторах. Я вставю в ступор от кликанья по десяткам уровней вложенности окошек конфигурации Студии :) Раньше под Windows действительно любили распространять готовые sln проекты примеров, но теперь и версий Студий слишком много, и монополию на компиляцию под Win они потеряли. В случае же с этим примером и с этой библиотекой CMake глубоко изучать не нужно, все уже создано за пользователя. В примере пользователю нужно только запустить CMake из директории, куда генерировать проект и указать директорию, куда скачены файлы примера. Если нужно, как вы писали выше, подключить библиотеку уже к существующему не-CMake проекту в студии, нужно сделать то же самое, но скачав только qluacpp, и указав дополнительно всего-лишь две опции: путь к .h файлу от lua и путь к .lib файлу от lua.
LUA C++
 
Цитата
mmonk1980 написал:
У вас example в файле README.md, выложить dll и проект .sln к нему...
Этот example был почищен и переведен в репозитарий qluacpp-tutorial, в который добавлен и проект CMake, генерирующий .sln ко всем Студиям. Одновременно он был убран из файла README.md, чтобы не путать пользователей. В этом же README.md указаны требования: CMake, Lua 5.1, C++11 компилятор. Эти требования означают, что данный софт надо иметь на своем компьютере и уметь им пользоваться. В том числе, невозможно пользоваться библиотекой, если не уметь генерировать CMake проект под выбранную среду по вкусу (например, .sln под Студию 2015) и невозможно пользоваться библиотекой, если не уметь подключать библиотеки в выбранной среде. Как сгенерировать .sln, указано выше. Как подключить библиотеки в Студию, тоже указано по ссылке на MSDN. В скомпилированной форме библиотека не распространяется: не хочу, чтоб ходили бинарники, которые потом перестают работать или чем-нибудь заражены. Кроме того, смысла в этом нет, если делаешь продукт сугубо для программистов. Файл .sln от библиотеки прикладывать невозможно по указанным выше причинам (не портабелен между компьютерами). Файл .sln от примера будет ссылаться на непортабельный .sln библиотеки, его надо от руки переделывать под каждую новую Студию и т.п.
LUA C++
 
Я не могу на вашем компьютере набрать команду "cmake ... путь_где_создать_солюшн путь_куда_скачали_библиотеку". Создать проект под MSVS 2015 тоже не могу: у меня нет MSVS2015, да и я просто не помню как их создают там вручную. Не создавал их мышкой в Студии почти лет десять. Прислать сгенерированный тоже не могу: он генерируется с учетом путей на системе, на которой вызывается CMake, работать у вас не будет. Создавать от руки проект под каждую версию студии, плюс не под MS компиляторы, и распространять библиотеку так, я считаю шагом назад и уводить с современных средств генерации проектов тоже не хочу.
LUA C++
 
Библиотека компилируется как обычная статическая библиотека для Visual Studio. Если нужна компиляция в динамическую, то скорей всего достаточно вставить в CMakeLists.txt от qluacpp в директиве add_library: "SHARED", не проверял. Если хотите создать библиотеку так, как было задумано, просто генерируете солюшн от qluacpp как сказано выше, потом добавляете этот проект с библиотекой в свой проект примерно как описано в обучалке от Microsoft как пользоваться Студией (последний раздел): https://msdn.microsoft.com/en-us/library/ms235627.aspxТеоретически если желание все делать от руки, должно работать именно так.
LUA C++
 
Возможно, я не понял,что вы имели в виду в предыдущем сообщении, особенно под "Нужен .sln  и ваш example dll компилируется." Sln не генерируется cmake-ом? Или нужен только .sln от самой библиотеки qluacpp? Для этого нужно просто запустить
cmake -G "Версия студии" -Dпараметры_с_путями_к_Lua c:\path\directory\to\qluacpp
LUA C++
 
Цитата
mmonk1980 написал:
Ну хотя бы example и чтобы dll делал? У меня на VS 2015 проект и знаю как это либу прикрутить (это не помогло: пример плагина и пошаговая инструкция к нему, включая генерацию проекта под студию). Нужен .sln  и ваш example dll компилируется.
Пунк 6.2.1.
https://github.com/elelel/qluacpp-tutorial/blob/master/doc/ru/6_Building.md
LUA C++
 
https://github.com/elelel/qluacpp-tutorial
Пример плагина и пошаговая инструкция к нему, включая генерацию проекта под студию.
LUA C++
 
Цитата
mmonk1980 написал:
Никак не хочет компилировать в Visual Studio, может есть (.sln) проект?

С какими именно симптомами? .sln нет, но cmake должен успешно его генерировать (опция -G), т.к. для nmake все генерируется хорошо
Расширение потокобезопасных функций в QLUA
 
Цитата
swerg написал:
Т.е.нужно уметь выполнять заданную функцию под общим мьютексом, верно?
Под средствами синхронизации Quik'a. Официально нигде не говорится, что синхронизация происходит под общим мьютексом. Может быть, там несколько мьютексов на разные случаи. Вообще сейчас того же самого можно (наверное) и так добиться при помощи ssort. Функция ssort берет предиткат для определения порядка. В качестве этого предиката можно передать функцию которая а) гарантировано не изменит порядок сортировки и б) выполнит один раз нужный код с сайд-эффектом. Но не совсем очевидное использование.
Расширение потокобезопасных функций в QLUA
 
Пример:
Код
function my_fn()
  table.concat(t, "1")
end

Synchronized(my_fn)
... было бы эквивалентно текущему вызову sconcat()

Иными словами, текущие потокобезопасные функции внутри выглядят видимо как-то так:
Код
safe_function_concrete(args) {
  if (safe_to_execute()) {
     function_concrete(args);
  }
}
Это можно было бы генерализировать в
Код
safe_function(concrete_fn) {
  if (safe_to_execute()) {
     concrete_fn()
  }
}
где safe_to_execute() - синхронизационный код, concrete_fn - конкретная функция, которую будет указывать пользователь.
Расширение потокобезопасных функций в QLUA
 
В документации QLUA описано 8 потокобезопасных функций, которые выполняют конкретные действия после  выполнения действий по синхронизации main/callback-потоков. Предложение: добавить функцию Synchronized, которая бы исполняла бы только действия по синхронизации потоков, после чего выполняла бы внутри указанную пользователем функцию, не выполняя никаких других заранее определенных конкретных действий. Сейчас этого можно добиться используя "не по назначению" текущие потокобезопасные функции.
Порядок создания callback-обработчиков
 
Цитата
swerg написал:
Цитата
El El   написал:
Цитата
swerg   написал:
Любопытно, кстати: зачем генерировать обработчики в run-time?
Один из случаев, который был бы удобен многим, чтобы упрощать слежение корректности стейта. Сейчас, например, если есть поведение, зависящее от стейта, то нужно в каждом коллбеке делать проверки на то, от чего он зависит. Если бы можно было переназначать обработчики, то вся вариативность бы укладывалась бы в одом if-е в каком-нибудь OnInit, где инициализируются и переменные, и функции обратного вызова. Таким образом, можно было бы добиться инкапсуляции данных и поведения "для бедных" в Lua.
можно как-то на примере?

Было бы:
Код
Инициализация_скрипта:
  x = внешние_данные
  if (x == A)
    дополнительная манипуляция над данными
    if (x.z == 1)
       манипуляция_состоянием1...
       OnAllTr ade = My_OnAllTrade1
       OnQu ote = My_OnQuote1
       ...
    if (x.z == 2)
       манипуляция_состоянием2...
       OnAllTr ade = My_OnAllTrade1
       OnQu ote = My_OnQuote2
       ...
    if (x.z == 3)
       манипуляция_состоянием3
       OnAllTr ade = My_OnAllTrade1
       OnQu ote = My_OnQuote2
       ...
  else ...  
Это эквивалентно динамическому полиморфизму в ООП языках.

Сейчас пришлось бы делать так:
Код
Инициализация_скрипта:
  x = внешние_данные

OnQuote:
  if (x == A)
     манипуляция над частью данных
     if (x.z == 1)        
       OnAllTr ade = My_OnAllTrade1
       OnQu ote = My_OnQuote1
       ...
     if (x.z == 2)
       ...
     if (x.z == 3)

OnAllTrade:
  разбор для всех тех же случаев
В итоге получается, что вся вариативность поведения разбросана внутри каждого коллбека и нужно раздублировать все проверки на состояние внутри.
Чуть более сложный сценарий, в зависимости от состояния переназначать коллбеки, например, чтоб не вызывался один OnAllTrade, пока не сработал другой колбек (сейчас альтернатива, опять же, засунуть все в один OnAllTrade и делать там разбор случаев).
Вобщем-то даже в Lua при всей ее примитивности заложена философия first-class функций, и такая работа с функциями, как динамическое переназначение на имя другой лямбды, вполне в ее духе.
Порядок создания callback-обработчиков
 
Цитата
Sergey Denegin написал:
я пользуюсь такой штукой:
...
Таким образом он его снова перекомпилирует, и если его текст был изменен, то все функции начинают работать "по-новому".
У меня все перекрасно работает. можете попробовать
У меня сама проблема решена (в С++), я скорее хотел прояснить, как же оно на самом деле задумано, с учетом того, что некоторые колбеки успешно переопределяются. В документации ничего про то, когда их можно определять, я не нашел.
Порядок создания callback-обработчиков
 
Цитата
swerg написал:
Любопытно, кстати: зачем генерировать обработчики в run-time?
Один из случаев, который был бы удобен многим, чтобы упрощать слежение корректности стейта. Сейчас, например, если есть поведение, зависящее от стейта, то нужно в каждом коллбеке делать проверки на то, от чего он зависит. Если бы можно было переназначать обработчики, то вся вариативность бы укладывалась бы в одом if-е в каком-нибудь OnInit, где инициализируются и переменные, и функции обратного вызова. Таким образом, можно было бы добиться инкапсуляции данных и поведения "для бедных" в Lua.
Порядок создания callback-обработчиков
 
Цитата
s_mike@rambler.ru написал:
К сожалению, связывание обработчиков идет в момент запуска скрипта и создание обработчика в процессе работы скрипта уже ни к чему не приводит.

На мой взгляд это недоработка и связывание должно быть динамическим, но "начальник всегда прав" (((
В этом есть резон, например, чтобы не обращаться при каждом OnQuote в Lua за текущим адресом обработчика. Однако, часть работает так, часть - по-другому, логики не прослеживается. Если это из соображений скорости, то хорошим выходом было бы создание API, типа UpdateCallbackHandlers, которую скриптер мог бы вызывать эксплицитно, если что-то поменял.
Страницы: 1 2 След.
Наверх