Технический вопрос по терминалу MT4 - вызов другого процесса из индюка в MT4 приводит к поступлению новых тиков в start() и проблемам синхронизации

 

Здравствуйте.

У меня вообще-то сильно технический вопрос, наверное, в первую очередь к разработчикам, но спец. форум переведён в readonly с направлением с вопросами сюда.. Так что вот пишу тут и надеюсь таки получить ответ, т.к. мой брокер ещё не перешёл на МТ5 (да и я свой код далеко не сразу на мт5 смогу перевести):

Итак, ситуация: когда индюк МТ4 выполняет длительный расчёт данных (например, при обработке самого первого тика, когда работает на истории), то в это время в start() новые тики не приходят. Т.е. не бывает так, что с приходом нового тика будет вызван start(), когда start() не закончил обработку старого тика. Т.е. обработка тиков ведётся последовательно синхронно возможно с пропуском тиков, которые пришли во время длительной работы прошлого start(). Это хорошо, удобно и понятно. При этом в качестве признака можно ещё отметить, что поскольку индюк исполняется в потоке GUI, то при выполнении таких длительных расчётов GUI "замораживается".

Но если в процессе работы индюка вдруг потребуется вызывать алгоритмы, работающие в другом процессе, то начинаются проблемы - во время синхронного вызова функций другого процесса в start() продолжают поступать новые тики и GUI продолжает отвечать на события! Понятно, что внутри-то конечно вызов другого процесса по определению асинхронный, но с точки зрения потока, который исполняет start() индюка (поток ли GUI?) - вызов процесса синхронный; управление не возвращается (и start() не завершается), пока не будет получен результат. Описанное явление порождает проблемы с синхронизацией работы такого индюка, адекватностью IndicatorCounted() и т.д. и т.п.

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

Требуемый результат: мне нужна нормальная синхронизация в индюке, корректный IndicatorCounted() и не нужен приход новых тиков во время работы start() :))

Вопрос краткий - мне придётся её обеспечивать самому, или я изначально что-то делаю не так (не должно таких эффектов наблюдаться в принципе) и можно что-то подкрутить? Какие мысли? :)

Спасибо.

зы: возможно, вводной информации мало - уточняйте, пожалуйста. Разработчикам готов предоставить демокод на тестирование.

 

Речь идет о проблемах в одном конкретном индикаторе?

Непонятно описана проблема. В индикаторе асинхронный вызов другого процесса и нужно синхронизировать вызов процедуры start() с обработкой во внешнем процессе? В таком виде это и не проблема вовсе, решается на раз. Может что-то другое? Перечитываю и не понимаю.

 

Да, проблема в одном индикаторе, но полагаю, она будет в любом индикаторе, построенном по такому принципу.

Давайте по другому опишу:

Если я ничего не путаю, то метатрейдер предполагает by design, что поток (thread в терминологии WinAPI), вошедший в старт() для обработки тика, не вернётся из него до тех пор, пока этот тик не будет обработан. При этом, пока старт() не вернётся, сам метатрейдер не вызовет его повторно (для обработки нового тика). Здесь всё правильно? Таким образом гарантируется, что старт() всегда вызывается последовательно и никогда не бывает ситуации, когда старт() для нового тика будет вызван в момент, когда работает старт(), вызванный для предыдущего тика. Вроде тут всё правильно?

А я наблюдаю следующее явление, когда где-то в дебрях старт() вызывается API Математики MathLink, которое вызывает другой процесс: не смотря на то, что старт() для прошлого тика ещё не завершился (другой процесс работает долго, но поток простаивает ожидая результатов), вызывается старт() для нового тика. Т.е. получается, что предлагается обработать новый тик, при том, что ещё не завершена обработка старого тика... Ну, и соответственно, в случае, когда я просто буду отсеивать такие "неправильные" старт(), IndicatorCounted() будет выдавать впоследствии неправильные значения...


Я кажется понял суть проблемы)) Надо было просто её более подробно продумать, что сейчас и произошло в процессе написания))) В общем, результаты от другого процесса ожидаются с помощью API WaitFor*(), что ставит поток в режим ожидания. Поскольку метатрейдер такой подлости от индюка не ожидает, и это делает как раз гуишный поток, то поступающие в него сообщения гуи системы размораживают его (поток) для их обработки, и если в это время приходит новый тик - запускают новый старт() для его обработки (т.к. считается, что если пришли в обработку новых гуи-сообщений, значит старый старт уже закончился). Обработка нового старт(), получается, происходит в контексте всё того же потока, просто как бы "вложена" в ожидание отработки исходного старт().

И таким образом получается, что это наверное мне придётся заботиться о правильной обработке (выпиливанию) таких "шальных" стартов() и правильному подсчёту IndicatorCounted()...

Собственно, 4 вопроса осталось:

1) правильна ли гипотеза, объясняющая наблюдение?

2) каких эффектов следует ожидать от аналогичного алгоритма, работающего в советнике? А под тестером?

3) можно ли надеяться на апдейт МТ4 на правильную обработку такой ситуации? (похоже, тут будет достаточно одного флага, показывающего, что прошлый старт() не завершился и его проверки перед вызовом нового)

4) будет ли МТ5 правильно обрабатывать такие ситуации?

Спасибо.

 

Скорее всего не WaitFor, а на уровне механизма обработки очередей сообщений. Индикаторы в потоке гуя и от обработчиков сообщений пляшут.

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

Ситуация чревата внутрипрограмными ошибками, поэтому я бы предположил, что требуется её корректное решение собственными силами, а не "обход".

Выпиливание лишних стартов можно попробовать даже на уровне mql через статические переменные устанавливаемые в начале процедуры и сбрасываемые в её конце. Но ещё вопрос как там разработчики переменных свои и объекты хранят, скорее всего это будет некорректным решением.

Пока мыслей как надежно решить проблему не имею.

 

Ндя.... Перспективы, конечно, аховые, но за честность и конкретику - отдельное искреннее спасибо :)

Корректное решение, конечно, требуется, но случай не тривиальный и требует хорошего знания нутра мт4... В частности, на что ещё кроме IndicatorCounted() может такое поведение влиять?

Особенно, меня, конечно, поведение в советнике беспокоит, ибо если оно приведёт к потерям - придётся менять метатрейдер на другую платформу вместе с брокером :(

 
Да, я пока именно так через статические переменные и сделал (а есть ли ещё варианты? ;) )... Да и эмуляция IndicatorCounted() - полюбому требуется правильная, ибо код совместен с советником, где этой функции банально нет... Индюк-то - черт с ним, а вот что будет в советнике при таких пирогах - очень тревожно...
 
Советник исполняется не в гуишном потоке, а в отдельном, и при использовании советника такой проблемы не должно быть.
 
gip:

Скорее всего не WaitFor, а на уровне механизма обработки очередей сообщений. Индикаторы в потоке гуя и от обработчиков сообщений пляшут.

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

Ситуация чревата внутрипрограмными ошибками, поэтому я бы предположил, что требуется её корректное решение собственными силами, а не "обход".

Пока мыслей как решить проблему не имею.


а если распределить задачу на несколько терминалов, на одном - индикатор работает, на другом советник пашет,

данные работы индюка, скажем через файл передавать в советник

кроме всего этого еще и ресурсы процессора будут распределятся граммотно, если процессор многоядерный.

 
А вообще-то я начинаю припоминать, такое уже обсуждалось. Наверное можно на форуме порыться и найти.
 
OlegTs:

а если распределить задачу на несколько терминалов, на одном - индикатор работает, на другом советник пашет,

данные работы индюка, скажем через файл передавать в советник

кроме всего этого еще и ресурсы процессора будут распределятся граммотно, если процессор многоядерный.


Это будет безумно медленно :(

Даже внутри одного процесса МТ4 данные между индюком и советником передавать нерентабельно (разница в скорости чуть ли не на порядки в сравнении со встраиванием кода индюка прямо в советник)...

Но если будет глючить...блин... Боюсь, придётся рассматривать и этот вариант, спасибо за идею...

 
Gorinych:

Собственно, 4 вопроса осталось:

1) правильна ли гипотеза, объясняющая наблюдение?

В принципе, да.

2) каких эффектов следует ожидать от аналогичного алгоритма, работающего в советнике? А под тестером?

То же самое, плюс к этому GUI будет полностью жив, т.к. советник работает в своем потоке.

3) можно ли надеяться на апдейт МТ4 на правильную обработку такой ситуации? (похоже, тут будет достаточно одного флага, показывающего, что прошлый старт() не завершился и его проверки перед вызовом нового)

Это правильная обработка. Это проблема пользователя, и решать ее тоже не разработчикам.

Надо просто сделать эмуляцию синхронного вызова, что нетяжело. Или просто учесть в коде асинхронность выполнения, что на мизер сложнее.

4) будет ли МТ5 правильно обрабатывать такие ситуации?

Да, как и МТ4 их сейчас отрабатывает правильно, оставляя на усмотрение пользователя :) .

Причина обращения: