在C ++中用线程实现多个定时器的最安全的方法

时间:2017-08-12 23:30:46

标签: c++ multithreading timer

正如标题所说,我正在寻找在C ++中实现多个计时器的最佳方法(而不是c ++ 11)。 我的想法是有一个单一的pthread(posix)来处理定时器。 我需要至少4个定时器,3个周期和1个单发。 最小分辨率应为1秒(最短计时器)和最长分辨率15小时。 所有计时器都应该同时运行。

这些是我想到的不同实现(我不知道它们在线程环境中是最安全的还是最简单的实现):

1)使用itimerspec,sigaction和sigevent结构如下:

static int Tcreate( char *name, timer_t *timerID, int expireMS, int intervalMS )
{
   struct sigevent         te;
   struct itimerspec       its;
   struct sigaction        sa;
   int                     sigNo = SIGRTMIN;

   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = app;
   sigemptyset(&sa.sa_mask);
   if (sigaction(sigNo, &sa, NULL) == -1)
   {
       perror("sigaction");
   }

   /* Set and enable alarm */
   te.sigev_notify = SIGEV_SIGNAL;
   te.sigev_signo = sigNo;
   te.sigev_value.sival_ptr = timerID;
   timer_create(CLOCK_REALTIME, &te, timerID);

   its.it_interval.tv_sec = 0;
   its.it_interval.tv_nsec = intervalMS * 1000000;
   its.it_value.tv_sec = 0;
   its.it_value.tv_nsec = expireMS * 1000000;
   timer_settime(*timerID, 0, &its, NULL);

   return 1;
}

2)使用clock()并检查时差,如下所示:

std::clock_t start;
double duration;
start = std::clock();
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;

3)使用这样的计时器:

auto diff = tp - chrono::system_clock::time_point();
  cout << "diff:" << chrono::duration_cast<chrono::minutes>(diff).count()
       << " minute(s)" << endl;
  Days days = chrono::duration_cast<Days>(diff);
  cout << "diff:" << days.count() << " day(s)" << endl;

请将这些视为想法,而不是实际的工作代码。

您对此有何看法?

2 个答案:

答案 0 :(得分:0)

由于所有计时器创建显然都是通过单个API(即控制代码可以看到所有计时器),因此您可以完全避免信号或繁忙循环,并保留一个排序的计时器列表(如{{1}按截止日期键入),并使用(例如)pthread_cond_timedwait等待条件变量。条件变量互斥锁保护定时器列表。

如果您安排一个新的计时器,其截止时间早于当前的&#34;下一个&#34;计时器,您需要唤醒睡眠线程并安排调整后的睡眠(如果不是这个要求,您可以使用普通std::map或其他)。这一切都发生在与条件变量相关联的互斥锁中。

您不必使用条件变量,但它们似乎是最干净的,因为相关的互斥锁自然用于保护计时器列表。您也可以使用usleep在一个semaphone上构建它,但是在内部套接字,管道或类似的东西上sem_timedwait之上构建它,但是你会被单独控制多个 - 对定时器队列的线程访问。

答案 1 :(得分:0)

如果您的计时器线程仅对负责定时器,并且最小分辨率为1秒,并且时间不需要那么精确(即+/- 0.1秒是好的然后,定时器线程的一个简单实现是只睡1秒,检查需要触发的任何定时器,并重复,如下面的伪代码:

repeat:
  sleep 1
  t = t+1
  for timer in timers where timer(t) = true:
    fire(timer)

硬件将填充存储定时器的结构 - 可能是定时器将由其他线程设置,可能由多个线程设置,可能尝试同时设置定时器。建议使用一些标准数据结构(如线程安全队列)将消息传递给定时器线程,然后在每个循环中更新定时器集合本身:

repeat:
  sleep 1
  t = t+1
  while new_timer_spec = pop(timer_queue):
    add_timer(new_timer_spec)
  for timer in timers where timer(t) = true:
    fire(timer)

要考虑的另一件事是fire(timer)的本质 - 这里要做的事情真的取决于使用定时器的线程的需求。也许只是设置一个他们可以读取的变量就足够了,或者这可能会激发线程可以监听的信号。