#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "To test the functionality of the GlobalVariableSetOnCondition function,"
#property description "it is necessary to run the EA on several charts simultaneously."
#define EXP_NAME StringSubstr(__FILE__, 0, StringLen(__FILE__)-4) // 程序名称
#define MUTEX EXP_NAME+"_MUTEX" // 互斥全局变量名
#define DELAY 5000 // EA 仿真的毫秒数
input long InpExpMagic = 0; /* Expert magic number */ // EA ID. 如果为 0,则使用图表 ID
union LongDouble // 从 double 中写入和检索 long 值的联合
{
long lvalue; // long 型值
double dvalue; // double 型值
};
//--- EA 全局变量
long ExtExpMagic; // EA ID
ulong ExtStart; // EA “计算”开始的那一刻
//+------------------------------------------------------------------+
//| EA 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 如果指定了零值,则将图表 ID分配给 EA ID
ExtExpMagic=(InpExpMagic==0 ? ChartID() : InpExpMagic);
//--- 创建互斥体,如果有错误,返回初始化错误
if(!MutexCreate())
return(INIT_FAILED);
//--- 初始化成功
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| EA 去初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- 如果互斥体被 EA 捕获,则释放互斥体
if(MutexGetExpertID()==ExtExpMagic)
MutexRelease();
//--- 清理干净
Comment("");
}
//+------------------------------------------------------------------+
//| EA 分时报价处理函数 |
//+------------------------------------------------------------------+
void OnTick()
{
//---如果没有互斥体,则创建它;如果有错误,退出直到下一个分时报价
if(!GlobalVariableCheck(MUTEX) && !MutexCreate())
return;
//--- 获取终端全局变量中设置的 EA ID
long magic=MutexGetExpertID();
//---如果 ID 属于此 EA,则模拟其工作
if(magic==ExtExpMagic)
{
//--- 如果 EA “工作”完成,释放互斥体
if(EAProgressHandler(ExtStart))
MutexRelease();
return;
}
//--- 被另一个 EA 捕获的互斥体
else
{
//--- 如果互斥体已经释放
if(magic==0)
{
//--- 占用互斥并记住工作访问时间
if(MutexOccupy())
{
PrintFormat("%s: Mutex is occupied by %s",Symbol(), ExpertIDDescription());
ExtStart=GetTickCount64();
}
return;
}
//--- 互斥体仍被另一个 EA 占用 - 禁止工作
else
return;
}
/*
两个相同 EA 分别运行于 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
我们可以看到,第一个占用互斥体的 EA 是分时报价首先到达的 EA
在工作循环完成后,如果分时报价再次出现在这里,
同一 EA 会再次占用互斥体
*/
}
//+------------------------------------------------------------------+
//| EA 操作处理模拟器 |
//+------------------------------------------------------------------+
bool EAProgressHandler(ulong start)
{
//--- 如果自处理程序开始工作以来已经过了指定的时间
if(GetTickCount64()-start>=DELAY)
{
//--- 在日志中报告处理程序的完成情况,
//--- 为处理程序设置新的开始时间并返回“true”
PrintFormat("%s: %s end", Symbol(), ExpertIDDescription());
start=GetTickCount64();
return(true);
}
//--- EA 计算模拟器的操作时间尚未完成 -
//--- 在日志中报告下一个分时报价
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);
}
//+------------------------------------------------------------------+
//| 以字符串形式返回 EA ID |
//+------------------------------------------------------------------+
string ExpertIDDescription(void)
{
return("Expert "+(string)ExtExpMagic);
}
|