тоже ничего дельного не покажет, надо по всем сделкам смотреть. А вот у нас все сделки по интелу, то есть вообще все после указанного времени. Спешл фор ю спецоперацию провели. Тут как-то было обсуждение, мол да вы чо, да чтобы рынок просадить миллиард влить надо. А вот оно как на практике, ткнули одним лотом и собрали урожай. Причем явно знали, по какой цене у вас продажа, подставили покупку в точности как заказано.
Александр Волфовиц, отличный пример, как прострелить себе ногу в многопоточном окружении. Выше верно написали, мейн меняет hcc на строку как раз после проверки типа в колбеке. Обращение к глобальной переменной из разных потоков должно быть атомарным. Я б посоветовал 1) упаковать все три hcc, mcc, scc в луа-таблицу; 2) в мейне строить локально эту таблицу (а еще лучше специальную функцию написать, ее возвращающую) и сохранять в глобальную переменную одним присвоением; 3) в колбеке создавать локальную копию опять-таки одним присвоением и далее работать только с ней.
TGB написал: Обкладывать синхронизацией все используемые сишные функции в однопоточном QLua для меня неожиданное решение.
А их никто и не обкладывал. Это не аркино решение, сам луа так устроен. Все очень просто, байткод всегда выполняется под локом, а когда надо вызвать сишную функцию, лок снимается и после возврата захватывается снова. Арке надо было только реализовать lua_lock/lua_unlock, все остальное уже готово. Тут хочу добавить, что если вы в своей длл определяете сишный колбек, то он тоже без лока выполняется (в отличие от луа-колбека). И это отличное место, где можно прострелить себе ногу.
Цитата
TGB написал: Вообще, в однопоточном QLua можно было бы практически полностью отказаться от всякой синхронизации и от модификации исходного Lua.
Исходный луа практически не модифицирован, добавлены только колбеки, предусмотренные в луа для взаимодействия с хостом. Сама qlua.dll ничего не хачит, использует луа как положено через стандартный апи, что местами не очень эффективно, но идеологически правильно.
Насчет однопоточности - так можно было сделать с самого начала, теперь что-то переделывать, похоже, поздновато. И у такого решения есть минус, на момент выборки сообщения в потоке скрипта общее состояние квика уже другое. Сравните с виндовыми очередями сообщений, где позиция мыши и нажатые клавиши сохраняются для каждого сообщения, какими они были на момент генерации сообщения, это вот пример, какие сложности возникают. И арке пришлось бы тоже подобным заниматься, закончилось бы полным дампом состояния, прицепленным к каждому сообщению. А как есть - вам дали колбек, квик вас ждет в колбеке, вы забираете то, что нужно именно вам и отправляете в мейн. Тоже не все гладко, кое-что все равно асинхронно даже в колбеке, но это мизер по сравнению с адом, который был бы с наглухо зашитыми в qlua очередями.
local run = true
local nshow = 0
function OnAllTrade()
if nshow < 10 then
PrintDbgStr('OnAllTrade')
nshow = nshow + 1
end
end
function dummy(i)
local a = math.sqrt(math.sqrt(1.0 * i) * math.sqrt(2.0 * i))
end
function main()
PrintDbgStr('Before loop')
for i = 0, 10000000 do
dummy(i)
end
PrintDbgStr('After loop')
end
TGB написал: Между сообщениями 'Before loop' и 'After loop' ни одно сообщение 'OnAllTrade' не вклинилось.
Значит увеличьте длину цикла или усложните вычисления в dummy, цикл просто быстро закончился. Вы обнаружили, что на время вызова любой сишной функции (а не только sleep) луа снимает лок, и сделали неправильный вывод, подумав только на sleep. В качестве такой функции может выступить и message, как в примере, и любая встроенная в луа библиотечная функция, и любая функция qlua. И так всегда было, это не новость в последней версии.
TGB, неправда. Если бы было правдой, в следующем скрипте между сообщениями 'Before loop' и 'After loop' ни одно сообщение 'OnAllTrade' вклиниться не могло бы (слипа в мейне нет, следовательно, колбеки не должны выполняться, согласно вашей модели). А они вклиниваются.
Код
local run = true
local nshow = 0
function OnAllTrade()
if nshow < 100 then
message('OnAllTrade')
nshow = nshow + 1
end
end
function dummy(i)
local a = math.sqrt(1.0)
end
function main()
message('Before loop')
for i = 0, 10000000 do
dummy(i)
end
message('After loop')
end
Хотел было, но Диего любит наворотить в проекте нетривиальностей, что в двух словах не объяснишь, так что проще самому собрать (не тестировано вообще никак, может и нерабочее получилось).
Так-то компилятор (одного файла) выглядит вот так и запускается в самом квике (куда уж совместимее-то)
Код
-- compilation arguments
local srcname = getScriptPath() .. '\\test.lua'
local dstname = getScriptPath() .. '\\test.out'
local strip_debug_info = false
-- the compiler itself
function main()
local chunk, err = loadfile(srcname, 't')
if nil == chunk then
error('Compilation error:\n' .. err)
end
local bin = string.dump(chunk, strip_debug_info)
local f = io.open(dstname, 'wb')
if nil == f then
error('Unable to create the destination file')
end
f:write(bin)
f:flush()
f:close()
end
С учетом sleep(1) есть неиллюзорные шансы, что мейн завершается раньше sendTransaction из колбека. Что будет, если в OnTransReply строку run = nil перенести после sendTransaction?
Алексей написал: непонятно, то что этот буфер функция сама не освобождает после отработки и приходится ждать сборщика мусора.
Утечкой это нельзя назвать, утечка это когда утекло с концами. В конкретном случае буфер выделяется под строку с отформатированной датой. Луа отформатировал дату, пытается пихнуть строку на стек, а такая строка уже есть от прошлого вызова, отсюда периодичность прирастания минутная или секундная в зависимости от формата. Затем дата поменялась, луа таки засунул новую строку в стек, а старая улетела в мусор и дело за коллектором, когда он там соблаговолит. Еще и поинтересней есть закидоны, коллектор определяет лимит, исходя из занятой памяти, и иногда при медленном нарастании может решить, что вообще все ок и прибираться рановато, и при следующем подходе опять, и так будет постепенно память прирастать, вроде и мусор, а вроде и прибираться перманентно рановато. Дергайте collectgarbage, если напрягает.
Ага. Смотрите, вы купили позавчера канистру бензина и вылили в бочку, вчера купили еще одну и вылили в ту же бочку, сегодня вы хотите из бочки залить в бак. Ваш вопрос: как залить именно тот бензин, что был куплен позавчера? Ответ: а никак, он весь одинаковый. Заливайте сколько надо и считайте, что залили именно позавчерашний.
TGB написал: можно бы было как то использовать и его исходники
Они уже присутствуют в 8.11 в несколько модифицированном виде, только не работают, то ли не включили асинхронные исключения при компиляции, то ли замодифицировали до смерти.
Roman Azarov написал: предоставьте, пожалуйста, скрипт, на котором она воспроизводится
Сейчас я могу предоставить кое-что получше. Вот здесь архив с тем же скриптом и - новое - (весьма приблизительной) копией вашей lua53.dll, собранной из обычного луа 5.3.5 и палок. Распаковать все в папку рабочего места с заменой оригинальной lua53.dll, запустить скрипт. Через секунду скрипт выбросит ACCESS VIOLATION - смотрите, как исключение будет обработано, - точно так же, как любая другая ошибка луа, без повреждения состояния квика, без деактивации кнопки "запустить" и прочих прелестей. Сравните с поведением оригинальной lua53.dll. Вот что ожидалось увидеть после добавления приведенного выше кода, но что-то пошло не так.
Уже выкладывал скрипт + длл для выбрасывания исключений в колбеках, может облегчат работу. Удобнее всего в OnStop бросать, при запущенном скрипте ставим брейкпойнты перед и после LUAI_TRY, жмем остановить, убеждаемся, что на брейкпойнте ДО остановились, жмем продолжить и по идее должны остановиться на брейкпойнте ПОСЛЕ, а по факту улетаем в qlua.dll. У меня, к сожалению, сорцев и символов нет, наглядно на скринах показать не получится.
Roman Azarov написал: в чем именно заключается проблема?
У меня - ни в чем, я как бы предложил некое улучшение, его как бы реализовали, мои тесты показали, что оно никогда не сработает в текущем виде почему-то. Как брейкпойнт поставить я думаю в арке все знают, куда поставить написано выше. Тут вопрос надо ли оно кому-то. Ежли нет, так мне меньше всех.
swerg написал: Волшебно работать с какой-то одной версией - это поможет.А вот с двумя разными одновременно в рамках одной dll...
Тоже можно, хотя на самом деле я считаю, что создание одной универсальной длл - это создание себе геморроя. В том числе жаль, что арка пошла по этому пути, а не сделала отдельный плагин под каждую версию луа. Как говорится, сложность программы растет, пока не превысит способностей программиста, так зачем приближать этот момент.
Александр написал: lua_getextraspace - опять же надо загружать какую-то из этих DLL
Не то чтобы загружать, а получить хэндл. Если длл отсутствует, то и печалиться не о чем, она никак нас не могла запустить. Вот вариант извлечения прицепленной к стейту версии. Возвращает версию числом или 0, если ничего не удалось выудить. На 5.3 и 5.4 попробовал, 5.1 нет под рукой, чисто "а чо ей не работать-то".
swerg написал: мы должны иметь две полных структуры адресов Lua-API функций для разных версий Lua и вставлять проверку в каждую функцию библиотеку, доступную для Lua-скрипта, переключаясь на адреса нужной версии Lua для каждой интерфейсной функции нашей библиотеки....
Вот так в квике и сделано. Есть lua_getglobal51, lua_getglobal53, теперь и lua_getglobal54, и есть lua_getglobalX, которая из переданного стейта выуживает версию и дергает нужный вариант функции. И так все. Сам квик всегда использует lua_*X, для него разницы нет, в какой версии скрипт выполняется, если еще десяток версий добавят, основной код и не заметит. Честно говоря, думал, что это временное-переходное решение, но вот с добавлением 5.4 стало ясно, что так и останется.
Александр написал: Я изучил структуры lua_State для луа 5.3 и 5.4 и они различны. Если поле status <> 0, то это lua5.3, иначе lua5.4.
Тоже в эту сторону смотрел, показалось ненадежным. Там есть еще одно интересное место, если уже привязываться к версии и немного хачить: к стейту прицеплена юзердата, сам квик по ней версию и определяет (несколько запутанным способом, я не понял, как именно). Получить можно с помощью экспортируемой luaI_getextraspace или (раз уж хачить) просто как ((char *)pstate) - 8, оно во всех версиях луа одинаково. А уж дальше порыться там.
Уже обновил и даже попробовал. Код с транслятором в lua53.dll увидел (и в lua54.dll тоже), а вот работающим его не увидел. Предполагаю потому, что lua53.dll собрали без флага /EHa, других объяснений не могу придумать. Транслятор перед вызовом колбека ставится, но при исключении в колбеке оно улетает по-прежнему в qlua.dll и ловится уже там, то есть по-прежнему весь хвост в luaD_rawrunprotected и выше не выполняется. Чтобы это увидеть, достаточно поставить брейкпойнт в luaD_rawrunprotected сразу после блока LUAI_TRY и бросить из колбека access violation или что-то подобное. Если исключение поймано, квик встанет на брейкпойнте, но этого не происходит, ближайшее место, где удалось его остановить, это транслятор в qlua.dll, то есть где и раньше.
Как запретить QUIK добавлять инструменты самостоятельно?, Кто-то подкидывает в Текущие торги торговые инструменты по своему усмотрению, как бездомных котят..
Выше глупость написал, конечно, мы и так знаем, из какой длл lua_version дернули. Но вот хотел проверить на практике и узрел очень интересную штуковину. Тксть внимание на экран. Запускаем скрипт, грузящий нашу длл, через "запустить в луа 5.3.5", смотрим, какой стейт нам дали Теперь запускаем через "запустить в луа 5.4.1", смотрим, какой стейт нам дали Это изыск дизайна или это лютый косяк?
Александр написал: Не подходит, т. к. в Lua 5.4 lua_version просто возвращает номер версии, а при передаче в luastate от Lua 5.4 в функцию lua_version от Lua 5.3 происходит ACCESS_VIOLATION.Еще варианты?
Еще вариант - не передавать в lua_version указатель на стейт, а передавать NULL, это защитит от акцесс виолейшена (как?). В этом случае 5.3 вернет указатель на статический номер версии, а 5.4 вернет число с номером версии. Далее исходим из факта, что указатель никак не может быть меньше 64 килобайт, винда из этого тоже всегда исходит, так что безопасно. Значит, ежли получили меньшее число - это напрямую номер версии, а если большее - это указатель на номер версии, разыменовываем и получаем сам номер. Костыльное решение, конечно, но рабочее.
swerg написал: 2) В списке исправленных недоработок есть несколько пунктов про Lua (пункты 10, 11, 12, 13)Подразумевается, что указанные в них проблемы исправятся только при использовании Lua 5.4 ? или для Lua 5.3 они исправлены тоже?
Значицо, что мы видим по некоторым из этих пунктов.
1. С lua_checkstack (п.11) вроде все порешали, натыкали везде и вроде везде с правильным размером. Считаем вопрос закрытым. Работать будет во всех версиях, это уже над луа находится.
2. С SEH-исключениями (п.12) пока могу сказать только про 5.3. Видно, что старались, но, кажется, забыли флаг /EHa компилятору поставить, поэтому транслятор в lua53.dll теперь есть, но не срабатывает при исключении, исключение таки долетает до qlua.dll и ловится уже там старым транслятором и старой ловушкой, которые, к счастью, пока не убрали. Так что тут еще надо допиливать.
В целом, беглым взглядом глядя, по луа работа большая проделана.
P.S. Для сотрудников арки и внешних желающих поковырять исключения предлагаю простой комплект - длл, генерирующая разные виды исключений (+сорцы), и скриптик к ней. Раскомментируем в скрипте по строчечке и смотрим, как квик соответствующее исключение вылавливает. В арке могут также поставить бряк на новый транслятор и убедиться, что никогда он не выполняется.
Виталий написал: Как сам факт поддержки CLR (без каких-либо вызовов) влияет на выгрузку библиотеки?
Влияет так, что загрузчик, видя clr в загружаемом модуле, загружает дотнет, и дальнейшим циклом жизни модуля управляет уже дотнет. Квик ни сном ни духом не ведает, что в него вперли аппдомен и его надо прибивать, соответственно никто его и не прибивает, соответственно длл выгружена не будет.
Виталий написал: если есть ошибка в dll, насколько припоминаю, квик вывалит ошибку и захлопнется. Разве нет?
Не обязательно, lua_error из длл можно смело генерировать, они ловятся как обычные ошибки скрипта. Плюсовые исключения тоже ловятся, даже некоторые seh, но эти повреждают квику кишки и потом могут быть последствия. А вот если стек попортить, квик ничего не заметит и может на этом потом или упасть, или накосячить.
Виталий написал: Во-вторых, Старатель в комменте выше предоставил исчерпывающий пример, если моих кодов мало.
Он подтвердил то, что в моем вопросе подразумевалось: при ошибке в длл она не выгружается. Это не очень здорово, но это и не нормальная рабочая ситуация. По существу варианта два: а) в 8.10 что-то накосячили с выгрузкой (проверить не могу); б) в вашей длл есть ошибка (проверить не могу). Из уже показанного я бы предложил перед lua_pushstring добавить lua_checkstack. Хотя вряд ли это причина, это намекает на то, что длл сделана без должного пристрастия к деталям, в коих диавол.
Игорь написал: Вы по сути предлагаете условный лимитник по другой бумаге
Он называется "по другой", но "по той же самой" прекрасно работает тоже. В отличие от прочих видов стопов позволяет поставить с любым условием и в любую сторону. Но трейлить не будет, да. По моему скромному мнению трейлинг не работает не потому, что он в квике плохо сделан (хотя и плохо тоже), а потому, что эта идея в принципе нерабочая.
Оно все фигня, даже если кажется, что не фигня. На конструктивную фигню арка, глядишь, и патчик сделает, а на вопли "тут все неправильно, все в топку" - нет.
Игорь написал: Но ведь и локальные максимумы при срабатывании «стоп-цены по другой бумаге» будут также отсчитываться от цены СЛЕДУЮЩЕЙ сделки ПОСЛЕ срабатывания этой стоп-цены.
Этот вид стопа ничего вообще не отсчитывает, он выставляет лимитник с фиксированной ценой и все. Тут у многих проблема, как я понимаю, в осознании факта, что цену вам не квик предлагает, это не дилерский рынок. Если прошел тик по вашей стоп-цене, он уже прошел, в стакане уже нет этого уровня, его уже слопали, ваш лимитник попадает в стакан на то, что там осталось. В частности, иногда там вообще ничего может не быть, тупо пустой стакан.
TGB написал: А если local gcrunner = {} (локальная переменная) то __gc срабатывает при при любом запуске collectgarbage (в том числе, и до завершения скрипта).
Есть такое. Значит, коллектор не считает объявление переменной ссылкой на нее. Значит, надо глобально ее объявлять или хотя бы иметь где-то ссылку на нее.
Насчет функций. Если gcrunner глобальный, то выскочит сообщение, мол используете прибитый файл, а это значит, что io еще не выгружена, это ее сообщение. Получается, файл прибит не в результате выгрузки библиотеки. Я не нашел, чтобы квик явно где-то файлы закрывал или даже чтобы явно выгружал библиотеки, хотя может где и есть. Принимаем как данность. Строго говоря, финализаторы это не деструкторы, никакой порядок их выполнения не гарантируется, так что теоретически все ок, а как практически это обходить, надо думать.
local gcrunner = (function()
local t = {}
setmetatable(t, { __gc = function()
local t = tid
tid = nil
if t then DestroyTable(t) end
message('file type is ' .. io.type(file))
file:write("__gc\n")
file:close()
end })
return t
end)()
Владимир написал: Я чуть не всю жизнь занимался сложными базами данных, и утверждаю, что ЕСТЬ "в базе данных терминала адреса строки или чего то ещё, описывающей сущность". По той простой причине, что доступ к любому элементу данных ДОЛЖЕН быть обеспечен.
Особенно в trie, там одни строки и есть. Но есть нюанс.
Владимир написал: можно просто передать указатель на запись
... и держать лок хранилища, чтобы оно не дай бог что-нибудь там внутри не подвинуло, пока юзер в колбеке ковыряется. Вариант выше упомянут и признан идиотским, каковым он и является. Прочие варианты тоже перечислены и это полная группа, отлаживай не отлаживай. Раз хранилище асинхронное, оно вольно асинхронно очиститься в том числе, и индекс тоже инвалидирутеся. Крэша он не вызовет, а нил вернет, и объяснять придется.
Не в этом случае. Хранилище асинхронное. Можно либо сразу вытащить всю запись и передать по значению, как и сделано, либо держать лок до возврата колбека, что есть идиотизм, либо передать индекс записи и объяснять потом пользователям, почему иногда возвращается ничего. Максимальное улучшение тут видимое - посмотреть при старте скрипта на сигнатуру колбека и не заполнять табличку, если она ему не нужна. Но это из области полировки.