2013-05-15 6 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), тогда обратный вызов таймера не будет вызываться. Я запутался в функциях таймера лейбэва. Не понял ли я таймер? И как разрешить обратный вызов таймера после истечения тайм-аута после перезапуска таймера?

ответ

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