在C中的工作线程中实现计时器的方法

时间:2011-01-27 13:37:11

标签: c multithreading unix timer

我有一个工作线程可以从管道中获取工作。像这样的东西

void *worker(void *param) {
  while (!work_done) {
    read(g_workfds[0], work, sizeof(work));
    do_work(work);
  }
}

我需要在同一个线程中实现一个1秒的计时器来做一些关于工作的簿记。以下是我的想法:

void *worker(void *param) {
  prev_uptime = get_uptime();
  while (!work_done) {
    // set g_workfds[0] as non-block
    now_uptime = get_uptime();
    if (now_uptime - prev_uptime > 1) {
       do_book_keeping();
       prev_uptime = now_uptime;
    }
    n = poll(g_workfds[0], 1000); // Wait for 1 second else timeout
    if (n == 0) // timed out 
       continue;
    read(g_workfds[0], work, sizeof(work));
    do_work(work);   // This can take more than 1 second also
  }
}

我正在使用系统正常运行时间而不是系统时间,因为在此线程运行时系统时间可能会发生变化。我想知道是否还有其他更好的方法来做到这一点。我不想考虑使用另一个线程。使用alarm()不是一个选项,因为它已被同一进程中的另一个线程使用。这是在Linux环境中实现的。

3 个答案:

答案 0 :(得分:3)

我同意webbi在答案中写的大部分内容。但他提出的使用时间而不是正常运行时间的问题存在一个问题。如果系统时间“向前”更新,它将按预期工作。但是如果系统时间缩短了30秒,那么30秒内就不会完成簿记,因为(now_time - prev_time)将是负数(除非使用无符号类型,否则它将继续工作)。

另一种方法是使用带有CLOCK_MONOTONIC的clock_gettime()作为clockid(http://linux.die.net/man/2/clock_gettime)。如果你不需要比秒更小的时间单位,那就有点乱了。

此外,添加用于检测向后时钟跳转的代码也不难。

答案 1 :(得分:2)

我找到了一种更好的方法,但使用timerfd_create()系统调用是特定于Linux的。它负责系统时间的变化。以下是可能的伪代码:

void *worker(void *param) {
  int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);  // Monotonic doesn't get affected by system time change
  // set timerfd to non-block 
  timerfd_settime(timerfd, 1 second timer);     // timer starts 
  while (!work_done) {
    // set g_workfds[0] as non-block
    n = poll(g_workfds[0] and timerfd, 0); // poll on both pipe and timerfd and Wait indefinetly 
    if (timerfd is readable) 
       do_book_keeping();
    if (g_workfds[0] is readable) {
       read(g_workfds[0], work, sizeof(work));
       do_work(work);   // This can take more than 1 second also
    }
  }
}

看起来更清晰,read()上的timerfd会在do_work()需要很长时间的情况下返回额外的时间,这非常有用,因为do_book_keeping()期望每秒调用一次。

答案 2 :(得分:0)

我在你的代码中发现了一些奇怪的东西......

poll()有3个args,你传递的是2,第二个arg是你在第一个param的struct数组中传递的结构数,第三个参数是超时。

参考:http://linux.die.net/man/2/poll

除此之外,对我来说这对我来说没问题,当然不是最好的,但是如果不涉及另一个线程或警报(等)就可以了。 您使用时间而不是正常运行时间,如果系统日期发生变化,它可能会导致一个错误,但随后它会继续工作,因为它会更新并继续等待1秒,无论什么时候都是。

相关问题