Поток событий. Как контролировать и сделать событие idle ? (+ решено)

 

Есть одна проблема - нужно сделать обновление некой функции, но быстрее чем предлагает MQL по таймеру - меньше 1 секунды.
Вариант решения - сделал отправку события самому себе - EventChartCustom в OnChartEvent .

Все работает очень быстро. Но появилась вторая проблема в том, что очередь сообщений не успевает выгребаться. переполняется.

То есть например при клике на объекте - событие CHARTEVENT_OBJECT_CLICK прийдет не сразу, а только после того как произойдет изымание всех преыдущих событий из очереди.
А как вы понимаете очередь событий наглухо забивается EventChartCustom.

Вобщем нужно добиться плотного контролируемого обновления некоторой функции, но при этом, чтоб

- не было никакого бесконечного цикла типа while (true)
- но и чтоб OnChartEvent откликался сразу же как происходит событие чарта.

Как поступить в этой ситации? Может есть другой вариант с контролем отправки EventChartCustom?

Другими словами - как застаить MQL вызывать некую функцию чаще 1 секунды, но без никаких очередей.

----------

Самое простое решение (но с участием разработчиков) - дать возможность получать следующее событие из очереди событий, но не выходя из функции OnChartEvent .

Т.е. чтоб все пустые события от моего EventChartCustom выгребать за один раз. И не допускать загрузки очереди левыми событиями.

 

Если отправлять событие только при обработке OnChartEvent , очередь по логике переполняться не должна. Ты не везде это событие запускаешь случаем?

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

 
TheXpert:

Если отправлять событие только при обработке OnChartEvent , очередь по логике переполняться не должна.

Не, она как раз и переполняет сама себя. EventChartCustom вызывается в OnChartEvent. И происходит плотный поток событий. С одной стороны то что нужно, а с другой - чартовые события пробиваются долго.

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

Думал я так, но ничего не придумал. Опиши схему обмена?
 
sergeev:
Думал я так, но ничего не придумал. Опиши схему обмена?

Есть индюк (разные потоки, наверное так будет лучше). Он ловит события 1. В событии желательно передавать всю нужную информацию для обратной передачи.

Индюк отправляет событие 2 отправителю события 1.

Советник ловит событие 2 и опять отправляет событие 1, на событие 1 советник ессно вообще никак не реагирует.

А если через фейковый советник вообще лепота -- спать можно.

 

Идея понятна.  но не сработает. это будет сродни пропуска одного события.

Но я проверил только что такой простой алгоритм

int rest=0;
int all=0;
bool click=false;
//------------------------------------------------------------------    OnInit
int OnInit() { EventChartCustom(0, 0, 0, 0, ""); return(0); }
//------------------------------------------------------------------    OnChartEvent
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
        if (id==CHARTEVENT_OBJECT_CLICK) click=!click;
        if (!click) { EventChartCustom(0, 0, 0, 0, ""); all++; }
        else rest++;
        
        string txt="all="+string(all)+"  rest="+string(rest);
        SetButton(0, "btn", 0, txt, clrWhite, clrDarkBlue, 150, 150, 200, 50, 0, 9, "Tahoma", click);
        ChartRedraw(0);
}
//------------------------------------------------------------------ SetButton
void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false)
{
        ObjectCreate(achart, name, OBJ_BUTTON, wnd, 0, 0); ObjectSetInteger(achart, name, OBJPROP_CORNER, corn); 
        ObjectSetString(achart, name, OBJPROP_TEXT, text); ObjectSetInteger(achart, name, OBJPROP_STATE, state);
        ObjectSetInteger(achart, name, OBJPROP_COLOR, txtclr); ObjectSetInteger(achart, name, OBJPROP_BGCOLOR, bgclr); ObjectSetInteger(achart, name, OBJPROP_BORDER_COLOR, clrNONE);
        ObjectSetInteger(achart, name, OBJPROP_FONTSIZE, fontsize); ObjectSetString(achart, name, OBJPROP_FONT, font);
        ObjectSetInteger(achart, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(achart, name, OBJPROP_YDISTANCE, y);
        ObjectSetInteger(achart, name, OBJPROP_XSIZE, dx); ObjectSetInteger(achart, name, OBJPROP_YSIZE, dy);
        ObjectSetInteger(achart, name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(achart, name, OBJPROP_BORDER_TYPE, 0);
        ObjectSetString(achart, name, OBJPROP_TOOLTIP, text);
}

Все события работают как надо. Тормозов нет.

Но если в строке поставить два раза (или более) EventChartCustom,

if (!click) { EventChartCustom(0, 0, 0, 0, ""); EventChartCustom(0, 0, 0, 0, ""); all++; }

то будет тормоз в два раза.

Отсюда делаю вывод, что все работает  как надо, это у меня в коде есть двойной вызов EventChartCustom где то, и накапливается это событие.

Буду искать в коде. Пока что тему можно прикрыть.

 
sergeev:

Идея понятна.  но не сработает. это будет сродни пропуска одного события.

Нет. Да, я имел в виду таки что чарты различаются для события 1 и 2

(1) Есть подозрение, что для разных потоков это будет работать гораздо медленней.

(2) можно спать, если советник.

ну и в 2 раза (как минимум) медленней.

 
свой OnCustomTimer в миллисекундах


#define MSECTIMER 100
#define TIMEREVENT 111
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
   EventSetCustomTimer(MSECTIMER);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();

  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EventSetCustomTimer(int msec) 
  {
   EventChartCustom(0,TIMEREVENT,msec,NULL,NULL);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   static uint lasttick=0;
   if(id==CHARTEVENT_CLICK) 
     {
      Print("Click");
     }

   if(id==CHARTEVENT_CUSTOM+TIMEREVENT) 
     {
      uint current=GetTickCount();
      if(lasttick+lparam<=current) 
        {
         lasttick=current;
         OnCustomTimer();
        }
     }
   EventSetCustomTimer(MSECTIMER);
  }
//+------------------------------------------------------------------+


void OnCustomTimer() 
  {
//
  }
//+------------------------------------------------------------------+
посмотрел предыдущий код - да
а в OnChartEvent свич бы не помешал, на дефолт которого
EventSetCustomTimer
 
TheXpert:

Нет. Да, я имел в виду таки что чарты различаются для события 1 и 2

(1) Есть подозрение, что для разных потоков это будет работать гораздо медленней.

(2) можно спать, если советник.

ну и в 2 раза (как минимум) медленней.


Правду говорят - утро вечера мудреней. :)  Проблему решил. Получилось даже элегантно.

- вводим счетчик оправленных сообщений event_idle

- при отправке события передаем в LPARAM этот счетчик EventChartCustom(chart, VM_IDLE, event_idle, 0, "");

- а далее в обработчике OnChartEvent выгребаем все VM_IDLE сообщения до тех пор, пока приходящий параметр LPARAM не станет равный текущему event_idle.

примерно так

ulong event_idle=0; bool bidle;
void OnChartEvent(int iview, int id, long lparam, double dparam, string sparam)
{
    if (id==CHARTEVENT_CUSTOM+VM_IDLE)
    {
        if (event_idle>(ulong)lparam || bidle) { bidle=event_idle>(ulong)lparam; if (bidle) return; event_idle=0; } // если последнее посланное больше чем пришедшее, то сразу выходим
        event_idle++;
        ChartRedraw(m_chart); // обновили чарт
        EventChartCustom(m_chart, VM_IDLE, (long)event_idle, 0, ""); // отправили событие с указанием последнего счетчика
        return; 
    }
    EventChartCustom(m_chart, VM_IDLE, (long)event_idle, 0, ""); // отправили событие с указанием последнего счетчика

    /*
        обработка остальных событий
    */
}

таким образом никогда не наступит перебор по этому событию, так как все они будут изыматься.

Теперь скорость вполне устраивает и без перебора очереди событий :)

 
sergeev:

...Но появилась вторая проблема в том, что очередь сообщений не успевает выгребаться. переполняется.

Не могу найти ответа на вопрос: как влияет переполнение очереди событий на размер оперативной памяти? Если очередь событий оказалась переполненной, то куда деваются события, переполнившие очередь? Освобождается ли часть оперативной памяти, зарезервированной под те события, которые оказались "за бортом истории"?

Может быть, вопросы мои терминологически не выдержаны, но (надеюсь) суть проблемы передают. 

 
Yedelkin:

Не могу найти ответа на вопрос: как влияет переполнение очереди событий на размер оперативной памяти? Если очередь событий оказалась переполненной, то куда деваются события, переполнившие очередь?

в том и дело, что никуда. накапливаются.
 
sergeev:
в том и дело, что никуда. накапливаются.

Т.е., если очередь событий оказывается переполненной, то события, переполнившие очередь, "жрут безвозвратно" оперативную память, постепенно увеличивая размер потреблённой оперативной памяти? Но это же неправильно. Представляется, что "пролетевшие мимо кассы" события должны освобождать в итоге зарезервированную под них память.

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

Документация по MQL5: Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика
Документация по MQL5: Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика
  • www.mql5.com
Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика - Документация по MQL5
Причина обращения: