#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description"GlobalVariableSetOnCondition 함수의 기능을 테스트하려면"
#property description"여러 차트에서 동시에 EA를 실행해야 합니다."
#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 lvalue; // 롱 값
double dvalue; // 더블 값
};
//--- EA 전역 변수
long ExtExpMagic; // EA ID
ulong ExtStart; // "calculations" 시작 시점
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 0 값이 지정된 경우 EA ID에 차트 ID를 할당합니다.
ExtExpMagic=(InpExpMagic==0 ? ChartID() : InpExpMagic);
//--- 뮤텍스를 생성하고 오류가 있으면 초기화 오류를 반환합니다.
if(!MutexCreate())
return(INIT_FAILED);
//--- 초기화 성공
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
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를 실행한 결과EUR/USD 그리고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);
}
//+------------------------------------------------------------------+
//| Create mutex, set it to the locked state |
//+------------------------------------------------------------------+
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);
}
//+------------------------------------------------------------------+
//| Release 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, magic.dvalue, 0))
{
PrintFormat("%s: GlobalVariableSetOnCondition() failed. Error %d",__FUNCTION__, GetLastError());
return(false);
}
return(true);
}
//+------------------------------------------------------------------+
//| Return mutex value |
//+------------------------------------------------------------------+
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);
}
|