Насколько я понял, т.к. в моём случае параметр dwFlags у CreateEventA равен 0, то ResetEvent не требуется. Похоже, когда Виндовс по установленному коллбэком флагу события запускает main, то Виндовс сбрасывает этот флаг, поэтому в принципе возможна потеря возникновения события. Ясно что события не буферизуются. Ожидание множества событий тут по-моему не очень подходит, т.к. main должна отрабатывать при возникновении хотя бы одного события.
Такую книжку Рихтера (только в синей ламинированной обложке) я купил давно, тогда я ещё не программировал на Си. Пока что меня не интересует общая теория семафоров, светофоров и шлагбаумов: я сейчас конкретно переписываю скрипт с Луа на Си dll, отвлекаться на эксперименты неохота. Пока у меня обработка событий на Си происходит в коллбэках и я собираюсь перенести её в main с использованием очереди и объектов событий, как это у меня работает в Луа.
Насколько я понял, надо использовать параметр lpName в CreateEventA: коллбэки создают события со своими именами. Осталось уточнить: что будет, если оба коллбэка успеют создать события, а main ещё не запустилась для их обработки. Не будет ли потеряно второе событие?
и оба коллбэка OnAllTrade и OnQuote почти одновременно выдали
Код
SetEvent(evt)
При вторичной выдаче SetEvent(evt) эта установка события не выполнится? Теперь вызывается main и начинает их обрабатывать событие: она проверяет и обрабатывает общую очередь от обоих коллбэков. Это правильная работа с событиями?
Как надо по-минимуму изменить параметры CreateEventA, WaitForSingleObject и SetEvent, чтобы main знала, какой именно коллбэк выдал SetEvent(evt)?
nikolz написал: dll проще и быстрее отлаживать не в КВИКЕ, а в SCITE
Имеется в виду текстовый редактор https://ru.wikipedia.org/wiki/SciTE ? Не пойму, как в нём можно отлаживать dll для Quik, я пока что привык к консольному редактору Фара, в качестве отладки вывожу значения переменных в файл, как делали деды и прадеды...
Заметил такие сюрпризы с форматом %g: Число 10000.2345 выводится в виде 10000.2 Число 100000.2345 выводится в виде 100000 Формат %f работает без ошибок, но с правыми нулями.
В OnAllTrade получаю цену акции, а она там имеет тип double (в отличие от getQuoteLevel2, где она в виде строки). По какому сишному формату для printf можно вывести double без правых незначащих нулей, если неизвестно, сколько значащих цифр в дробной части? Формат %g это делает, есть ли там есть риск, что он может вывести число с экспонентой? Неужели в си это невозможно? Я с пом. поиска ответа не нашёл. А скрипт на Lua просто берёт и выводит это, как мне надо. Как он это делает, вручную удаляет в строке правые нули? https://learn.microsoft.com/ru-ru/cpp/c-runtime-library/format-specification-syntax-printf-and-wprin...
Спасибо, теперь ясно, почему память под скрипт уменьшалась.
А если короткой строке что-то присвоить, то алгоритм сложнее: она, как я заметил, заносится в стринг буфер, и если какой-то строке присваивается короткое значение, то в этом стринг буфере ищется по хэшу такая же строка и, если найдена, оживляется, а если такая строка не находится, то тогда создаётся новая.
Вы имели в виду, что, когда я длинной строке присваиваю "", то она сразу удаляется (вызывается free()), минуя сборщик мусора, и пересоздаётся (c выделением 56 байтов через malloc())?
В main написал: collectgarbage('stop'), но при присваивании нового значения длинной строке в окне скриптов вижу, как занимаемая этим скриптом память сразу сильно уменьшается. Как это объясняется?
Serge123 написал: причём, значение для ключа quantity заканчивается на подстроку ".0", которую необходимо удалять.
Извините, это я спутал quantity с bid_count/offer_count, где к числам в строке приписывается точка и 6 нулей. По этому поводу возникает вопрос: в случае отсутствия спроса/предложения в bid_count/offer_count возвращается символьный 0, как написано в док-ции, или этот 0 возвращается с привеском: "0.000000"?
Это трудно проверить, для этого надо поймать момент, когда какую-нибудь акцию 33-го эшелона все уже купили и все хотят только продать, а покупать уже никто не хочет.
6 мая у тикера LQDT поменяли класс бумаги с TQTF на TQTF_F. Сегодня запустил Квик, а он в окне графики не показывает график для LQDT за 6 мая, а последний день у него 3 мая... Хотя, 6 мая Квик показывал график за 6 мая. Приложение на Андроиде показывает историю за 6 мая, поэтому проблема в Квике...
funduk написал: Вы же хакер, можете заменить часть бинарника,
Я не хакер, я недавно перешёл на C, и часто приходится смотреть в справке по языку, как и чем что сделать. Я набираю программы в редакторе Фара и не пользуюсь отладчиками. Просто я слегка разобрался в структурах таблиц, строк и нодов...
paluke написал: А еще должна быть какая-то непустая реализация макросов lua_lock()/lua_unlock() в llimits.h
Ясно, спасибо, я как-то заметил, что в исходниках эти лок и анлок присутствуют в виде заглушек. Получается, что нельзя самому что-то для своего удобства изменить в исходниках и получить настроенную под себя dll для Квика...
bid TABLE Котировки спроса (покупки). При отсутствии спроса возвращается пустая строка
Видимо, должно быть "... возвращается пустая таблица"? Ведь bid это таблица... Аналогично надо исправить для таблицы offer.
А что сейчас возвращает getQuoteLevel2 при отсутствии спроса/предложения, пустую таблицу? Я не могу это проверить...
Далее, при описании структур таблиц bid и offer надо написать, что эти таблицы являются массивами из таблиц, каждая из которых состоит из двух пар ключ-значение, причём, значение для ключа quantity заканчивается на подстроку ".0", которую необходимо удалять. Это, чтобы не удивлялись... Неплохо бы привести пример для пояснения структуры всей этой таблицы для стакана.
Аналогичные исправления надо сделать в англоязычной версии этого файла, в Lua Interpreter.pdf.
Кстати, хотел спросить: почему на lua.org исходники даются для вер. 5.4.6, а бинарники лишь для вер. 5.4.2? В составе Квика lua54.dll откуда берётся: квиковцы компилируют её из исходников? Они что-то перед компиляцией меняют в исходниках Lua?
Не в моём примере структура, а в Lua структура в файле lobject.h:
Код
/*
** Header for a string value.
*/
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
} u;
char contents[1];
} TString;
Цитата
nikolz написал: "Один дурак может задать столько вопросов,что сто мудрецов не смогут ответить"
Ну так не задавайте...
Цитата
TGB написал: Далее: char* str_h = (char*) Адрес структуры; И с str_h (указатель открытый для записи) делаете все, что хотите (в пределах размера строки).
Я уже написал dll с прямым доступом, которая меняет содержимое и размер строки, он работает. Также работает пример с массивом и хождением по нодам с поиском элемента по ключу. М.б. по примеру Миши Флёнова напишу книжку "Lua глазами хакера" (за почасовую ставку школьной уборщицы).
TGB написал: Вам интересно стрелять по своим ногам?
Примеры хоть и работают, но ноги иногда чувствуют себя неуютно.
Цитата
TGB написал: для вас имеет смысл все, кроме интерфейса с QUIK, писать на C (а может быть на MASM ).
Надо как-то оценить, в каком случае будет быстрее работать и во сколько раз. Сейчас на 2-ядерном ЦП, подозреваю, что и поток Квика с коллбэками и поток с main могут выполняться на одном ядре, поэтому с переносом работы в поток main и ожиданием события может получиться полная ерунда, надо будет это проверить на 6-ядерном ЦП.
Сейчас gcc настолько хорошо оптимизирует, что я как-то написал оптимизированную программку на flat assembler, а на C аналогичная работала заметно быстрее...
nikolz написал: как вы предполагаете изменить значение локальной переменной. Она не передается как таблицы по указателю, поэтому Вы не получите к ней доступ в функции, а получите ее копию.
Странное рассуждение... Адрес структуры для локальной строки передаётся в виде указателя в параметре при вызове из Lua скрипта моей dll.
А вдруг кто-то знает, но не хочет сказать... Вот TGB, по-моему, глубоко копает.
paluke написал: Или вы хотите разбираться с тем, как поменять значение в обход api, c рисками неопределенного поведения, ради ускорения в ноль целых хрен десятых процента?
Да, хочу, чтобы кто-то знающий подтвердил, что это будет незаметно для Луа (меня беспокоит какой-то непонятный буфер удалённых строк), на будущее может пригодиться в хозяйстве. Только почему сразу ноль целых хрен десятых, а вдруг будет больше?
Здесь подразумевается, что str изменилась с пом. моей dll. Вопрос: будет ли после этого скрипт работать корректно? Зачем для этого выписывать эту dll, она просто изменяет байты в массиве с содержимым этой строки...
paluke написал: Где-то пролетала ссылка на библиотечку w32 для lua. Там есть CreateEvent / WaitForSingleObject. Надо попробовать, должно работать...
Сегодня на этом форуме читал старые споры и препирательства, в которых говорилось, что мьютексы работают медленно и подходят для синхронизации потоков из разных процессов. А в одном процессе надо использовать какую-то критическую секцию. Я пока не знаю, что это такое и как это сделать быстрее, чем с мьютексами...
paluke написал: Вот продали вы один лот ценой 1.3862, а получили 1.39 из-за округления.
А, что-то я о таком слышал. Но для этого надо иметь право продавать без очереди. Читал, что ММ имеет такое право. Интересно, у фонда какого-то банка ММом может быть другой банк?
Если есть просто строка Lua, ссылок на которую нет в таблицах, то изменение такой строки не повлечёт неожиданностей в работе скрипта? Возможные варианты: длина строки не меняется/уменьшается. Мне кажется, это может повлиять только на подсчёт хэша от этой строки, а кому он нужен в данном случае? Но, как я заметил по исходникам Lua, у Lua есть какой-то кэшбуфер удалённых сборкой мусора строк, я не понял, что это такое и для чего он используется...
Примечание: если dll уменьшает размер строки, то она корректирует это в поле длины строки (и если надо, типе строки: короткая/длинная строка).
Видимо, имелось в виду, что длл получает инфо, что коллбэк что-то записал в очередь, и длл запускает main, которая всё остальное время спит. Или что-то подобное.
nikolz написал: Кроме того, у меня нет sleep. Поэтому задержка на обработку любого колбека не более 0.1 ms. Это на порядки меньше чем задержка со sleep.
Здесь я не понял, о каком sleep идёт речь. У меня в скрипте sleep(10) используется один раз в main в цикле обработки очереди от коллбэков. В Lua по-моему нельзя прервать паузу, если в мой массив (очередь) коллбэк что-то записал.
Игорь М написал: Если вы на открытии сделки совершаете, то помимо непосредственно ваших сделок ещё и большой поток информации в эти моменты приходит, поэтому Квик это тяжело переваривает.
Да, я видел, что причина торможения во время моих сделок в том, что иногда почему-то идёт большое число мелких сделок, напр., десятки сделок по 1 акции. Я так и не могу понять, зачем кто-то выставляет заявки по одной акции, как будто кто-то отлаживает свою программу или что-то тестирует. Если нет потока мелких сделок, то торможения нет.
Игорь М написал: Предполагаю, что Сергей описывал ситуацию зависания при приходе его личных сделок ("когда идёт много моих сделок, я ясно вижу торможение") , хотя конкретики мало дал. Отключать алгоритм Нейгла ему смысла нет. Его никто не отключает и у всех всё работает, значит, не в нём дело.
Точно, я даже предположил, что особенно на задержку влияют звуковые сигналы. Какая нужна конкретика? Где-то до октября 2023 я и в утреннюю и в вечернюю сессии удачно выставлял заявки с пом. скрипта, иногда даже видел по содержимому стаканов в файле, что я в очереди первый. Первым быть не всегда хорошо, потому что во время премаркета бывает в сумме крупная встречная заявка, за это снимают деньги. Но потом перестало получаться попадать в начало очереди на вечерней сессии (а утром по-прежнему всё ОК). Такое впечатление, что мосбиржа вечером варьирует время начала приёма заявок в пределах 2 секунд. То ли вечером возникли какие-то задержки (в том числе с получением ответов от сервера на заявки). Поэтому я и решил попробовать вечером отключить алгоритм Нейгла, но от этого получился полный затык в работе Квика.
Вызвать regedit, перейти в ветку HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ и далее зайти в подветку, где есть параметр DhcpIPAddress, который равен моему IP. Добавить/изменить 2 параметра (вначале их там нет): DWORD 32 бита TcpAckFrequency и TCPNoDelay со значением 1. Для его восстановления надо установить эти 2 параметра в 0. Для вступления в силу изменённых параметров надо перезагрузить ПК.
Nikolay написал: Если речь была про задержку потока main, то да она должна быть.
Как раз хотел спросить: какую задержку выставлять в main после цикла обработки очереди от OnAllTrade и OnQuote? Я сделал 10 мс, может, есть более правильная задержка?