1

libev の ev_timer に問題があります。以下のコードを見てください。

static void timeout_cb(struct ev_loop *loop, ev_timer *timer, int revent) {
    printf("got an timeout event, current time %s\n", get_current_time());
}

int main(int argc, char *argv[]) {
    struct ev_loop *loop = ev_loop_new(0);
    ev_timer_init(&timer, timeout_cb, 5.0, 0.0);
    ev_timer_start(loop, &timer);
    ev_run(loop, EVRUN_NOWAIT);  // callback should not be called
    ev_timer_stop(loop, &timer); // stop the timer
    sleep(5);  // sleep 5 seconds, 5 is also the timer's timeout value
    // restart timer
    ev_timer_init(&timer, timeout_cb, 5.0, 0.0);
    ev_timer_start(loop, &timer);
    printf("timer start at: %s\n", get_current_time());
    printf("timer remaining: %f\n", ev_timer_remaining(loop, &timer));
    ev_run(loop, EVRUN_NOWAIT);
    return 0;
}

出力は次のとおりです。

timer start at: 14:53:49:137
timer remaining: 5.0000
got an timeout event, current time 14:53:49:137

タイマーを再起動した後、タイマーはすぐにトリガーされるため、これは奇妙ですが、5秒後にする必要があります。その理由は sleep(5) であることがわかりました。それを sleep(4) に変更すると、タイマー コールバックは呼び出されません。私は、liebev のタイマー機能について混乱しています。タイマーについて誤解していますか?そして、タイマーが再起動した後、タイムアウトが経過した後にタイマーコールバックを呼び出す方法は?

4

2 に答える 2

2

コードを変更する必要があります

ev_timer_init(&timer, timeout_cb, 5.0, 0.0);

ev_timer_init(&timer, timeout_cb, ev_time() - ev_now() + 5.0, 0.0);

libev はパフォーマンス上の理由からタイムスタンプをキャッシュし、すべてのイベント ループの前または後にのみタイムスタンプを更新するためです。5 秒間スリープした後、現在のリアルタイムT + 5は 、つまりになりますev_timeが、libev の現在のタイムスタンプはまだT、つまり ですev_now。それで、あなたはこのようなタイマーを初期化します

ev_timer_init(&timer, timeout_cb, 5.0, 0.0);

libev は、現在のタイムスタンプ + 5 でタイマーのトリガー時間を設定します。つまりT + 5、現在のリアルタイムでもあるため、すぐにトリガーされます。しかし、このようにタイマーを初期化すると

ev_timer_init(&timer, timeout_cb, ev_time() - ev_now() + 5.0, 0.0);

libev は、タイマーのトリガー時間を現在のタイムスタンプ puls ev_time() - ev_now() + 5.0、つまり に設定しますT + T + 5 - T + 5 = T + 5 + 5 = real time + 5。そのため、5 秒後にトリガーされます。

于 2017-05-17T07:35:31.597 に答える