#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Для проверки работоспособности функции GlobalVariableSetOnCondition"
#property description "необходимо запустить данного эксперта на нескольких графиках одновременно."
#define EXP_NAME StringSubstr(__FILE__, 0, StringLen(__FILE__)-4) // имя программы
#define MUTEX EXP_NAME+"_MUTEX" // имя глобальной переменной мьютекса
#define DELAY 5000 // количество миллисекунд эмуляции работы эксперта
input long InpExpMagic = 0; /* Expert magic number */ // идентификатор эксперта. При значении 0 используется идентификатор графика
union LongDouble // объединение для записи и получения long-значений из double
{
long lvalue; // long value
double dvalue; // double value
};
//--- глобальные переменные советника
long ExtExpMagic; // идентификатор эксперта
ulong ExtStart; // момент старта "расчётов" советника
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- присваиваем идентификатору эксперта идентификатор графика в случае, если задано нулевое значение
ExtExpMagic=(InpExpMagic==0 ? ChartID() : InpExpMagic);
//--- создаём мьютекс, при ошибке возвращаем ошибку инициализации
if(!MutexCreate())
return(INIT_FAILED);
//--- успешная инициализация
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- если мьютекс захвачен этим советником - освобождаем мьютекс
if(MutexGetExpertID()==ExtExpMagic)
MutexRelease();
//--- почистим за собой
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- если мьютекса нет - создаём, при ошибке - уходим до следующего тика
if(!GlobalVariableCheck(MUTEX) && !MutexCreate())
return;
//--- получаем идентификатор эксперта, записанный в глобальной переменной терминала
long magic=MutexGetExpertID();
//--- если идентификатор принадлежит этому эксперту - имитируем его работу
if(magic==ExtExpMagic)
{
//--- если "работа" эксперта завершена - освобождаем мьютекс
if(EAProgressHandler(ExtStart))
MutexRelease();
return;
}
//--- мьютекс захвачен другим советником
else
{
//--- если мьютекс уже освобождён
if(magic==0)
{
//--- занимаем мьютекс и запоминаем время доступа к работе
if(MutexOccupy())
{
PrintFormat("%s: Mutex is occupied by %s",Symbol(), ExpertIDDescription());
ExtStart=GetTickCount64();
}
return;
}
//--- мьютекс всё ещё занят другим советником - работать запрещено
else
return;
}
/*
результат запуска двух одинаковых советников на графиках EURUSD и AUDUSD:
EURUSD: Mutex is occupied by Expert 133829812107724569
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 end
EURUSD: Mutex is occupied by Expert 133829812107724569
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 end
AUDUSD: Mutex is occupied by Expert 128968168951083984
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 end
AUDUSD: Mutex is occupied by Expert 128968168951083984
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 end
EURUSD: Mutex is occupied by Expert 133829812107724569
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 end
EURUSD: Mutex is occupied by Expert 133829812107724569
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 end
AUDUSD: Mutex is occupied by Expert 128968168951083984
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 next tick
AUDUSD: Expert 128968168951083984 end
EURUSD: Mutex is occupied by Expert 133829812107724569
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 next tick
EURUSD: Expert 133829812107724569 end
видно, что первым мьютекс занимает советник, где тик пришёл первым
после завершения цикла работы, если опять тик пришёл первым здесь же,
опять этот же советник занимает мьютекс
*/
}
//+------------------------------------------------------------------+
//| Обработчик-эмулятор работы советника |
//+------------------------------------------------------------------+
bool EAProgressHandler(ulong start)
{
//--- если с момента начала работы обработчика прошло заданное время
if(GetTickCount64()-start>=DELAY)
{
//--- сообщаем в журнал об окончании работы обработчика,
//--- устанавливаем новое время начала работы обработчика и возвращаем true
PrintFormat("%s: %s end", Symbol(), ExpertIDDescription());
start=GetTickCount64();
return(true);
}
//--- время работы эмулятора расчётов советника ещё не завершено -
//--- сообщаем в журнале об очередном тике
else
{
PrintFormat("%s: %s next tick", Symbol(), ExpertIDDescription());
}
//--- время работы ещё не завершилось - возвращаем false
return(false);
}
//+------------------------------------------------------------------+
//| Создаёт мьютекс, устанавливает в заблокированное состояние |
//+------------------------------------------------------------------+
bool MutexCreate(void)
{
if(!GlobalVariableCheck(MUTEX))
{
LongDouble magic={};
magic.lvalue=ExtExpMagic;
ResetLastError();
if(!GlobalVariableSet(MUTEX, magic.dvalue))
{
PrintFormat("%s: GlobalVariableSet() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
}
return(true);
}
//+------------------------------------------------------------------+
//| Захватывает мьютекс |
//+------------------------------------------------------------------+
bool MutexOccupy(void)
{
if(!GlobalVariableCheck(MUTEX))
{
PrintFormat("%s: Error! Mutex is missing. First create it with MutexCreate()",__FUNCTION__);
return(false);
}
LongDouble magic={};
magic.lvalue=ExtExpMagic;
ResetLastError();
if(!GlobalVariableSetOnCondition(MUTEX, magic.dvalue, 0))
{
PrintFormat("%s: GlobalVariableSetOnCondition() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Освобождает мьютекс |
//+------------------------------------------------------------------+
bool MutexRelease(void)
{
if(!GlobalVariableCheck(MUTEX))
{
PrintFormat("%s: Error! Mutex is missing. First create it with MutexCreate()",__FUNCTION__);
return(false);
}
LongDouble magic={};
magic.lvalue=ExtExpMagic;
ResetLastError();
if(!GlobalVariableSetOnCondition(MUTEX, 0, magic.dvalue))
{
PrintFormat("%s: GlobalVariableSetOnCondition() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Возвращает значение мьютекса |
//+------------------------------------------------------------------+
long MutexGetExpertID(void)
{
LongDouble magic={};
ResetLastError();
if(!GlobalVariableGet(MUTEX, magic.dvalue))
{
PrintFormat("%s: GlobalVariableGet() failed. Error %d",__FUNCTION__, GetLastError());
return(WRONG_VALUE);
}
return(magic.lvalue);
}
//+------------------------------------------------------------------+
//| Возвращает в виде строки идентификатор советника |
//+------------------------------------------------------------------+
string ExpertIDDescription(void)
{
return("Expert "+(string)ExtExpMagic);
}
|