#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 ID0の場合、チャートIDが使用されている
union LongDouble // doubleからlong値を書き込むまたは取得するためのunion
{
long lvalue; // long value
double dvalue; // double value
};
//--- EAグローバル変数
long ExtExpMagic; // EA ID
ulong ExtStart; // EA の「計算」が開始される瞬間
//+------------------------------------------------------------------+
//| エキスパート初期化関数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- ゼロの値が指定されている場合、チャートIDをEA IDに割り当てる
ExtExpMagic=(InpExpMagic==0 ?ChartID() : InpExpMagic);
//--- ミューテックスを作成し、エラーが発生した場合は初期化エラーを返す
if(!MutexCreate())
return(INIT_FAILED);
//--- 正常な初期化
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| エキスパート初期化解除関数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- EA がミューテックスを取得している場合、ミューテックスを解放する
if(MutexGetExpertID()==ExtExpMagic)
MutexRelease();
//--- クリーンアップ
Comment("");
}
//+------------------------------------------------------------------+
//| エキスパートティック関数 |
//+------------------------------------------------------------------+
void OnTick()
{
//--- ミューテックスが存在しない場合は作成し、エラーが発生した場合は、次のティックまで待機する
if(!GlobalVariableCheck(MUTEX) && !MutexCreate())
return;
//--- 端末グローバル変数に設定されているエキスパート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;
}
/*
result of running two identical EAs on EURUSD and AUDUSD charts:
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!ミューテックスがない。まず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!ミューテックスがない。まず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);
}
|