0

我需要能够同时启动多个计时器,并明确知道计时器是否已停止或仍在运行。

#define RESEND_TIMEOUT  5

void timer_set_timeout(timer_t * timer, uint32_t timeout);
void timer_start(timer_t * timer);
bool timer_complete(timer_t * timer);
void signal_handler(int sig, siginfo_t *si, void *uc);

int main() {
    timer_t resend_timer;
    printf("starting timer\n");
    timer_start(&resend_timer);
    timer_set_timeout(RESEND_TIMEOUT);
    while(1) {

    if (timer_complete(&resend_timer))
        break;
    }
}

void timer_set_timeout(timer_t * timer, uint32_t timeout)
{
    struct itimerspec it_val;
    it_val.it_value.tv_sec = timeout;
    it_val.it_value.tv_nsec = 0;
    it_val.it_interval.tv_sec = 0;
    it_val.it_interval.tv_nsec = 0;
     if (timer_settime(*timer, 0, &it_val, NULL) == -1) {
         errExit("Could not set timeout");
     }
}

void timer_start(timer_t * timer)
{
    struct sigaction sa;
    struct sigevent sev;

    // establish signal handler
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = signal_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIG, &sa, NULL) == -1)
       errExit("Failed to establish signal handler");

    // create timer
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = timer;

    if(timer_create(CLOCK_MONOTONIC, &sev, timer) == -1) {
        errExit("Could not start timer");
    }
}

// return true if timer ended
bool timer_complete(timer_t * timer)
{
    if(timer_getoverrun(*timer) == 0)
        return false;
    else
        return true;
}

void signal_handler(int sig, siginfo_t *si, void *uc)
{
    printf("Timer ran out!\n");
    signal(sig, SIG_IGN);
}

信号处理程序在 5 秒后运行,但我无法知道计时器是否已结束或未使用 timer_complete。我尝试过: int timer_gettime(timer_t timerid, struct itimerspec *curr_value) 但我不知道为 curr_value 传递什么。我尝试声明一个itimerspec,但它给出的结果与getoverrun 相同。

我还尝试使用timer_settime 的标志TIMER_ABSTIME,但由于某种原因,计时器立即到期。

4

1 回答 1

0

您误解了表示计时器已完成的含义。

从一开始,计时器有 2 组值。一组是未来定时器将关闭的时间;另一个是间隔值,用于在计时器关闭后重新加载第一组。如果使用第一组但间隔值设置为零,则根据定义,它是一次性计时器。如果间隔值非零,则计时器将重新加载并永久触发,直到您将其关闭。您可以通过使用 将所有值设置为零来关闭它timer_settimer

所以在你的 timer_complete 应该是这样的:

// return true if timer ended
bool timer_complete(timer_t * timer)
{
    struct itimerspec its;

    if (timer_gettime(*timer, &its) == -1)
    {
        perror("timer_settime");
        exit(1);
    }

    If ((its.it_value.tv_sec == 0)  &&
        (its.it_value.tv_nsec == 0) &&
        (its.it_interval.tv_sec == 0) &&
        (its.it_interval.tv_nsec == 0))
        return true;
    else
        return false;
}

超支是另一种动物。基本上,操作系统不会多次排队计时器信号,甚至是实时信号,因为可能太多了。Overrun 告诉您在您的程序接收到信号之前发生了多少次计时器(可能是排队的信号)。

于 2013-11-06T21:31:07.957 回答