pthread_cond_timedwait的使用及疑问

来源:互联网 发布:四柱算命软件 编辑:程序博客网 时间:2024/05/21 17:50


条件变量是一种在并发编程中常用的同步原语。是一种通知机制,一个线程需要某种条件成立后,才能继续执行,如果条件不成立则阻塞等待条件成立,是wait端;另外的线程则是执行某些操作后,使条件成立,然后唤醒等待线程,是signal/broadcast端。

wait端的使用方式:

  1. 由于条件会被wait线程读取,被signal/broadcast线程修改,即写入。为了防止出现竞争,需要和mutex一起使用,使用mutex来保护条件。
  2. 在mutex已经锁住的情况下,才能调用wait。
  3. 由于spurious wakeup(虚假唤醒)的原因,wait函数返回并不代表条件已经成立,在wait函数返回后,需要再次判断条件是否成立。因此需要将wai调用放到while循环中。

wait端检测到条件不成立时,可以调用以下两个函数进行等待。

1 int pthread_cond_timedwait(pthread_cond_t *restrict cond,2               pthread_mutex_t *restrict mutex,3               const struct timespec *restrict abstime);4 int pthread_cond_wait(pthread_cond_t *restrict cond,5               pthread_mutex_t *restrict mutex);

这两个函数的区别是,第一个函数可以设置超时时间。这里主要说明第一函数的使用方法和我遇到的问题。timespec指定的是超时时刻的绝对时间,而不是相对时间,因此需要先获取当前时间,然后加上需要等待的时间才能得到用于设置的时间,当前时间通过gettimeofday获取。为简化操作,这里把这些操作封装为一个函数,用于设置以毫秒为单位的相对超时时间。我第一次写的获取绝对时间的函数如下:

复制代码
 1 void get_abstime_wait(int microseconds, struct timespec *abstime) 2 { 3   struct timeval tv; 4   int absmsec; 5   gettimeofday(&tv, NULL); 6   absmsec = tv.tv_sec * 1000 + tv.tv_usec / 1000; 7   absmsec += microseconds; 8  9   abstime->tv_sec = absmsec / 1000;10   abstime->tv_nsec = absmsec % 1000 * 1000000;11 }
复制代码

第一个参数指定超时的相对时间,比如传500,表示500毫秒后超时。但是这样写几乎肯定使wait端线程进入busy loop状态。因为这些计算的中间结果,超出了int类型的表示范围,溢出了。添加打印后会发现abstime->tv_sec是一个很小的值,因此调用pthread_cond_timedwait后,立即就超时返回了。因此正确的写法是使用long long来保存结果,long long 类型在linux上是64位的,因此肯定不会溢出。

复制代码
 1 void get_abstime_wait(int microseconds, struct timespec *abstime) 2 { 3   struct timeval tv; 4   long long absmsec; 5   gettimeofday(&tv, NULL); 6   absmsec = tv.tv_sec * 1000ll + tv.tv_usec / 1000ll; 7   absmsec += microseconds; 8  9   abstime->tv_sec = absmsec / 1000ll;10   abstime->tv_nsec = absmsec % 1000ll * 1000000ll;11 }
复制代码

使用pthread_cond_timedwait过程中遇到的另一个奇葩问题是,当时间被设置为1970年以前时,超时机制也会出问题。我的工作是搞嵌入式开发,遇到过一台设备的时钟芯片坏掉后,获取出来的时间有问题,导致时间被设置成了1970年以前,这竟然导致pthread_cond_timedwait长眠不醒。本来打算在ubuntu上重现一下,结果系统不让设置1970年以前的时间了,也许已经不支持1970年以前的时间了吧,就先不管了。如果那位大神知道怎么回事,麻烦通知小弟一声,小弟不甚感激。

0 0
原创粉丝点击