#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Para verificar a operabilidade da função GlobalVariableSetOnCondition"
#property description "é necessário executar este EA em vários gráficos simultaneamente."
#define EXP_NAME StringSubstr(**FILE**, 0, StringLen(**FILE**)-4) // nome do programa
#define MUTEX EXP_NAME+"_MUTEX" // nome da variável global do mutex
#define DELAY 5000 // quantidade de milissegundos de emulação do trabalho do EA
input long InpExpMagic = 0; /* Expert magic number */ // identificador do EA. Se o valor for 0, é usado o identificador do gráfico
union LongDouble // união para gravar e obter valores long a partir de double
{
long lvalue; // long value
double dvalue; // double value
};
//--- variáveis globais do EA
long ExtExpMagic; // identificador do EA
ulong ExtStart; // momento de início dos "cálculos" do EA
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- atribuímos ao identificador do EA o identificador do gráfico caso um valor zero tenha sido definido
ExtExpMagic=(InpExpMagic==0 ? ChartID() : InpExpMagic);
//--- criamos um mutex, em caso de erro retornamos erro de inicialização
if(!MutexCreate())
return(INIT_FAILED);
//--- inicialização bem-sucedida
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- se o mutex estiver capturado por este EA - liberamos o mutex
if(MutexGetExpertID()==ExtExpMagic)
MutexRelease();
//--- limpamos o que for preciso
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- se não houver mutex, criamos; em caso de erro, saímos até o próximo tick
if(!GlobalVariableCheck(MUTEX) && !MutexCreate())
return;
//--- obtemos o identificador do EA gravado na variável global do terminal
long magic=MutexGetExpertID();
//--- se o identificador pertence a este EA, imitamos seu trabalho
if(magic==ExtExpMagic)
{
//--- se o "trabalho" do EA foi concluído, liberamos o mutex
if(EAProgressHandler(ExtStart))
MutexRelease();
return;
}
//--- o mutex está capturado por outro EA
else
{
//--- se o mutex já foi liberado
if(magic==0)
{
//--- ocupamos o mutex e registramos o horário de acesso ao trabalho
if(MutexOccupy())
{
PrintFormat("%s: Mutex is occupied by %s",Symbol(), ExpertIDDescription());
ExtStart=GetTickCount64();
}
return;
}
//--- o mutex ainda está ocupado por outro EA - trabalhar é proibido
else
return;
}
/*
resultado da execução de dois EAs idênticos nos gráficos EURUSD e 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
é visível que o primeiro a ocupar o mutex é o EA onde o tick chegou primeiro
após a conclusão do ciclo de trabalho, se novamente o tick chegou primeiro aqui,
novamente esse mesmo EA ocupa o mutex
*/
}
//+------------------------------------------------------------------+
//| Manipulador-emulador do trabalho do EA |
//+------------------------------------------------------------------+
bool EAProgressHandler(ulong start)
{
//--- se desde o início do trabalho do manipulador passou o tempo determinado
if(GetTickCount64()-start>=DELAY)
{
//--- informamos no diário o término do trabalho do manipulador,
//--- definimos um novo horário de início do trabalho do manipulador e retornamos true
PrintFormat("%s: %s end", Symbol(), ExpertIDDescription());
start=GetTickCount64();
return(true);
}
//--- o tempo de trabalho do emulador de cálculos do EA ainda não terminou -
//--- informamos no diário sobre o próximo tick
else
{
PrintFormat("%s: %s next tick", Symbol(), ExpertIDDescription());
}
//--- o tempo de trabalho ainda não terminou, retornamos false
return(false);
}
//+------------------------------------------------------------------+
//| Cria um mutex, define-o para o estado bloqueado |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| Captura o mutex |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| Libera o mutex |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| Retorna o valor do mutex |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| Retorna como string o identificador do EA |
//+------------------------------------------------------------------+
string ExpertIDDescription(void)
{
return("Expert "+(string)ExtExpMagic);
}
|