pthread_cond_timedwait的使用及疑問


條件變量是一種在並發編程中常用的同步原語。是一種通知機制,一個線程需要某種條件成立后,才能繼續執行,如果條件不成立則阻塞等待條件成立,是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年以前的時間了吧,就先不管了。如果那位大神知道怎么回事,麻煩通知小弟一聲,小弟不甚感激。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM