如何使pthread_cond_timedwait()對系統時鐘操作有效?
考慮以下原始碼,它完全符合POSIX標準:
#include <stdio.h> #include <limits.h> #include <stdint.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> int main (int argc, char ** argv) { pthread_cond_t c; pthread_mutex_t m; char printTime[UCHAR_MAX]; pthread_mutex_init(&m, NULL); pthread_cond_init(&c, NULL); for (;;) { struct tm * tm; struct timeval tv; struct timespec ts; gettimeofday(&tv, NULL); printf("sleep (%ld)\n", (long)tv.tv_sec); sleep(3); tm = gmtime(&tv.tv_sec); strftime(printTime, UCHAR_MAX, "%Y-%m-%d %H:%M:%S", tm); printf("%s (%ld)\n", printTime, (long)tv.tv_sec); ts.tv_sec = tv.tv_sec + 5; ts.tv_nsec = tv.tv_usec * 1000; pthread_mutex_lock(&m); pthread_cond_timedwait(&c, &m, &ts); pthread_mutex_unlock(&m); } return 0; }
每5秒列印一次當前的系統日期,但是在獲取當前系統時間(gettimeofday)和條件wait(pthread_cond_timedwait)之間休眠3秒鐘.
在列印“睡眠(…)”之後,嘗試將系統時鐘設定為過去兩天.怎麼了?那麼,pthread_cond_timedwait現在等待兩天2秒,而不是像通常那樣等待2秒的時間.
我該如何解決?
如何編寫符合POSIX標準的程式碼,當用戶作業系統時鐘時,程式碼不會中斷?
請記住,即使沒有使用者互動,系統時鐘也可能會改變(例如,NTP客戶端可能每天自動更新一次時鐘).將時鐘擺在未來沒有問題,只會讓睡眠早起來,這通常沒有問題,你可以輕鬆地“檢測”並相應處理,但將時鐘設定為過去(例如因為是執行在未來,NTP檢測到並修復它)可能會造成很大的問題.
PS:
我的系統上不存在pthread_condattr_setclock()和CLOCK_MONOTONIC.對於POSIX 2008規範(“Base”)的一部分,這些規範是強制性的,但大多數系統仍然遵循POSIX 2004規範,而在POSIX 2004規範中,這兩個規範都是可選的(高階實時擴充套件).
有趣的是,我以前沒有遇到過這樣的行為,但是再一次,我並不習慣我的系統時間這麼多:-)
假設你是為了有效的原因,一個可能(雖然kludgy)解決方案是有另一個執行緒,唯一的目的是定期踢條件變數來喚醒任何如此受影響的執行緒.
換句話說,就像:
while (1) { sleep (10); pthread_cond_signal (&condVar); }
等待條件變數被踢指令碼的程式碼應該是檢查它的謂詞(要照顧虛假的喚醒),所以這不應該對功能產生真正的不利影響.
這是一個輕微的效能打擊,但每十秒鐘一次不應該是太多的問題.這只是為了照顧那些(無論什麼原因)你的等待時間等待很長時間的情況.
另一種可能性是重新設計您的應用程式,以便您根本不需要定時等待.
線上程需要被某些原因喚醒的情況下,它總是由另一個執行緒完成,該執行緒完全有能力踢出一個條件變數來喚醒一個(或廣播喚醒它們).
這與我上面提到的踢腳線非常相似,但是作為你的架構的一個組成部分,而不是一個螺栓.
http://stackoverflow.com/questions/7121212/how-to-make-pthread-cond-timedwait-robust-against-system-clock-manipulations