2013-05-15 94 views
0

我有ev_timer 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秒後。我發現原因是睡眠(5)。我改變它睡覺(4)然後定時器回調將不會被調用。我對liebev的計時器功能感到困惑。我對計時器有誤解嗎?如何讓定時器重啓後超時後調用定時器回調?

回答

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); 
1

你應該代碼

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將在當前時間戳加五設置定時器觸發的時候,也就是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。所以它會在五秒鐘後觸發。

+0

您應該在回答中添加更多上下文,以解釋爲什麼這會解決問題。 – Joe