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 将出于性能原因缓存时间戳,并且仅在每个事件循环之前或之后更新时间戳。休眠五秒后,当前的实时时间为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. 所以它会在五秒后触发。

于 2017-05-17T07:35:31.597 回答
1

我并不声称自己是 libev 方面的专家,但我发现使用 ev_suspend(loop) 和 ev_resume(loop) 会阻止您看到的行为。从手册页:

ev_suspend (loop)
ev_resume (loop)
    These two functions suspend and resume an event loop, for use when
    the loop is not used for a while and timeouts should not be
    processed.

例如:

ev_run(loop, EVRUN_NOWAIT);  // callback should not be called
ev_timer_stop(loop, &timer); // stop the timer
ev_suspend(loop); // suspend timer processing
sleep(5);  // sleep 5 seconds, 5 is also the timer's timeout value
ev_resume(loop); // resume timer processing
// restart timer
ev_timer_init(&timer, timeout_cb, 5.0, 0.0);
ev_timer_start(loop, &timer);

我还发现另一种可能的解决方案是使用 ev_timer_again() 而不是 ev_timer_start() 这也可以防止您报告的行为。

例如:

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_again(loop, &timer);
于 2013-05-15T15:06:11.170 回答