Особенности языка mql5, тонкости и приёмы работы - страница 270

 
Vladimir Simakov #:

Второй раз кнопка нажмется в то время, когда будут выполняться инструкции после вызова 

, но до выхода из текущего вызова OnChartEvent (тот же Print еще даже не начнет выполняться), и, по закону подлости, именно тогда создадутся все условия к тому, что бы произошел наиболее неблагоприятный сценарий)))). Бинго!!! Это будет эпичный и поучительный фейл)))

Вопрос: кто будет в этом виноват? 

Ответ: тот кто юзает асинхронщину в боевом коде, слабо представляя всю глубину возможных глубин и ту боль, которая там живет.

Это, что бы все могли понять, как это будет (нажать копку после появления Calculated):

Как-то так надо:

Спасибо, что указали на такой негативный вариант развития событий. Да решение предложено было сырое, непродуманное, но это было даже не решение а направление в котором можно идти.

У меня вопрос немного в другой плоскости. Так как в ООП я совсем никакой, ваш код мне ясен, но не совсем.

Подскажите, вот это без ООП равнозначно тому, что ниже с ООП?  И если не равнозначно, то в чём разница?

double Calc()
  {
   double Res = 0;
   for(int i = 0; i < 1e8; i++)
      Res += MathSin(MathRand());
   return(Res);
  }
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long&, const double&, const string&)
  {
   static bool Unlock = true;
   if(id == CHARTEVENT_KEYDOWN && Unlock)
     {
      Unlock = false;
      Print("Calculating...");
      Print(Calc());
      if(!EventChartCustom(0, 0, 0, 0, ""))
         Unlock = true;
     }
   if(id == CHARTEVENT_CUSTOM)
      Unlock = true;
  }
class EventLocker{
public:
   EventLocker(){
      m_lock = true;
   }
   ~EventLocker(){
      EventChartCustom(0, 0, 0, 0, "");
   }
   static void Unlock() {m_lock = false;}
   static bool Locked() {return m_lock;}
private:
   static bool m_lock;
};

bool EventLocker::m_lock = false;
//+------------------------------------------------------------------+
double Calc()
  {
   double Res = 0;

   for(int i = 0; i < 1e8; i++)
      Res += MathSin(MathRand());
   return(Res);
  }
//+------------------------------------------------------------------+

void OnChartEvent(const int id, const long&, const double&, const string&)
  {
   if(id == CHARTEVENT_KEYDOWN && !EventLocker::Locked())
     {
      EventLocker lk;
      Print("Calculating...");
      Print(Calc());
     }
   if(id == CHARTEVENT_CUSTOM)
      EventLocker::Unlock();
  }
 

const ulong KEY_LG_MCS=100; // задержка 

ulong keyBEnabledAfter=1;  // разрешена реакция на кнопку после заданного времени, или 0 запрещена вовсе

OnChartEvent(..) {

   ulong now=GetMicrosecondCount();

   if ( id==CHARTEVENT_KEYDOWN && ..) {

// нажата нужная кнопка

        if (keyBEnabledAfter!=0 && keyBEnabledAfter<now) {

             // разрешена обработка кнопки

             keyBEnabledAfter=0;  // запретим дальнейшую реакцию

             needsCalc=true;       // запустим вычиляндр

             // или прямо сразу вычиcлим Calc(); keyBEnabledAfter=GetMicrosecondCount()+KEY_LAG_MCS;

        }

   }

}

OnTimer() {

   if (needsCalc) {

      // что-то тут вычисляем

      if (calcDone) {

          // закончили вычислять

          needsCalc=false; // отметим это

          keyBEnabledAfter=GetMicrosecondCount()+KEY_LAG_MCS; // разрешим реакцию ена кнопку через KEY_LAG mcs

      }

   }

}

общий принцип в псевдокоде...По вкусу обернуть функциями или породить класс на ровном месте

 

Чем хорошо оборачивание в класс - это использование идиомы RAII.

Суть в следующем. При выходе из зоны видимости вызываются деструкторы объектов с локальным временем жизни в порядке обратным их объявлению. Поэтому, в коде:

void Foo(){
   TSomeClass something;
   ...
   DoSomething();
}

сначала будет вызван DoSomething, а только потом деструктор ~TSomeClass(). Теоретически, мы можем даже не иметь на руках исходного кода TSomeClass и не знать, что происходит в деструкторе.

Если же сделать так:

class TScoupe{
public:
   ~TScoupe() {DoSomething();}
};

void Foo(){
   TScoupe scope;
   TSomeClass something;
   ...
}

, то, гарантированно, сначала вызовется деструктор TSomeClass и только после этого, при выполнении деструктора TScoupe, позовется  DoSomething.

 
Dominik Egert #:
Если я правильно понимаю, речь идет о многопоточной безопасности?

Если это так, то ни одно из предложенных решений не является безопасным.

Для безопасности потоков обязательна атомарная операция, только одна функция в MQL позволяет это сделать, и здесь она не использовалась.

На самом деле, чтобы сделать OnEvent многопоточным, необходима критическая секция. Такую секцию можно построить с помощью

GlobalVariableSetOnCondition.

Или я не на том пути?

Использовать global variables вообще и для синхронизации, в частности, так себе затея, учитывая то, что их можно поменять из любого места терминала)

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

 
Vladimir Simakov #:

Использование глобальных переменных вообще и для синхронизации в частности - не лучшая идея, учитывая, что они могут быть изменены из любого места в терминале)

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

Хорошо, как вы говорите.

Для меня это очень похоже на многопоточность.
 
Vladimir Simakov #:

Чем хорошо оборачивание в класс - это использование идиомы RAII.

Суть в следующем. При выходе из зоны видимости вызываются деструкторы объектов с локальным временем жизни в порядке обратным их объявлению. Поэтому, в коде:

сначала будет вызван DoSomething, а только потом деструктор ~TSomeClass(). Теоретически, мы можем даже не иметь на руках исходного кода TSomeClass и не знать, что происходит в деструкторе.

Если же сделать так:

, то, гарантированно, сначала вызовется деструктор TSomeClass и только после этого, при выполнении деструктора TScoupe, позовется  DoSomething.

Всё, чего добивается программист с таким подходом - усложнение читаемости кода.
 
Наверное, имеет смысл заменить для обработки нажатия клавиш CHARTEVENT_KEYDOWN на CHARTEVENT_KEYUP
 
Andrey Dik #:

Кто-то смог запустить какую либо оптимизацию с применением Alglib?

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

Неужели никто не знает и не видел примера использования?

 
Andrey Dik #:

Неужели никто не знает и не видел примера использования?

Я использовал для прогноза волатильности по модели GARCH. Есть статья на сайте
 
Evgeniy Chernish #:
Я использовал для прогноза волатильности по модели GARCH. Есть статья на сайте

Там в статье используются именно методы оптимизации? Можно ссылку на статью, пожалуйста.

ЗЫ. Если я правильно понял, эта статья имеется ввиду?

Эконометрические инструменты для прогнозирования волатильности: Модель GARCH
Эконометрические инструменты для прогнозирования волатильности: Модель GARCH
  • www.mql5.com
В статье дается описание свойств нелинейной модели условной гетероскедастичности(GARCH). На ее основе построен индикатор iGARCH для прогнозирования волатильности на один шаг вперед. Для оценки параметров модели используется библиотека численного анализа ALGLIB.