2018年11月10日土曜日

[MQL4] OnTick() と OnTimer() は同一スレッドで動いている

@MetaTrader 4.00 Build 1090

Expert Adviser の OnTick() で何か重たい処理をしているとき1OnTimer() はどのように処理されるのか、調べてみました。

結論から言うと、以下のような動作をするようです。 (同一スレッド上で動いているか、少なくとも排他されている。)

  • OnTick() の処理中に OnTimer() のタイミングが来た場合、OnTick() 終了直後にOnTimer()が実行される(OnTimer() はペンディングされる)
  • ただし、2回以上ペンディングされたとしても、OnTick() 終了直後に実行される OnTimer() は1回のみ
  • ペンディングされたとしても、OnTimer() が呼ばれるタイミングには影響しない(EventSetTimer() が呼ばれた時点から指定間隔で呼ばれ続ける2

この動作、逆の場合も当てはまるようです。 つまり、OnTimer() で重たい処理をしていると、その間に呼ばれるはずだった OnTick() が無視されることになります3

また、OnTick() で重たい処理をしていても、同じように OnTick() が無視されます。

OnTick()OnTimer() ではなるべく重たい処理をしないようにすべきですね。 かつ OnTimer() の呼び出し頻度は少なめに。

確認環境

以下のような EA を作成し、タイミングをいろいろ変えて確認してみました。

Experts/ThreadTest.mq4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#property strict
 
static uint count = 0;
 
int OnInit()
{
    //--- create timer
    EventSetTimer(1); // 1秒(本来こんなに高頻度で呼ぶべきではない)
 
    return(INIT_SUCCEEDED);
}
 
void OnDeinit(const int reason)
{
    //--- destroy timer
    EventKillTimer();
}
 
void OnTick()
{
    count++;
    printf("OnTick %u start", count);
    Sleep(3000); // 3秒待つ
    printf("OnTick %u end", count);
}
 
void OnTimer()
{
    Print("OnTimer");
}
  1. 本来は、なるべく重い処理はしない方が良いけれど 
  2. ただし、多少の誤差はある 
  3. 最後の一回を除いて 
?