之前大家討論說pthread_cond_timedwait()介面不能用,如果需要逾時返回功能的話必須寫一個定時器來實現.但是該操作太昂貴了,其實可以直接使用該介面來實現逾時等待功能的,下面描述我對該介面的瞭解及用法,僅供參考.
1. POSIX提供了多種時鐘類型,其中包括以下兩種:
CLOCK_REALTIME: Systemwide realtime clock. 系統範圍內的系統時鐘,是個軟體時鐘,可以通過命令等方式修改該系統時間.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set. 表示單調時間,為系統起機時到現在的時間,不能被設定跟修改.
pthread_cond_timedwait()在沒有設定條件變數屬性的時候,預設用的是CLOCK_REALTIME軟體時間,因此在極端情況下會出現實際等待的時間與設定的逾時時間不同.
下面介紹下如何正確使用pthread_cond_timedwait()介面
2. 正確使用pthread_cond_timedwait()介面方式即將測量時間參照改為CLOCK_MONOTONIC,這個需要在初始化時設定條件變數的屬性,之後再設定逾時時間.例子如下:
ret = pthread_condattr_init(&(pthread_info.condattr));
if (ret != 0) {
exit(1);
}
ret = pthread_condattr_setclock(&(pthread_info.condattr), CLOCK_MONOTONIC);
ret = pthread_cond_init(&(pthread_info.cleanup_queue_wait), &(pthread_info.condattr));
…
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
PTHREAD_TASK_DBG(LOGS_DEBUG, "now time:%d\n", tv.tv_sec);
tv.tv_sec += 30;-這裡設定30秒後沒收到事件逾時返回
ret = pthread_cond_timedwait(&(pthread_info.cleanup_queue_wait), &(pthread_info.cleanup_queue_lock), &tv);
…
運行如下:
從上可以看出,使用該方式無論對系統時間設定為任何值時,系統已耗用時間都不會被修訂,同時該線程也不會被觸發返回,依舊是原先的30秒逾時.
3. 其實使用CLOCK_REALTIME作為測量時間參照也是可行的,只是在極端的情況下(如在擷取當前系統時間後系統時間馬上被修訂)時,這個逾時時間就不正確了,不過這是小機率事件.
例子如下:
struct timespec tv;
tv.tv_sec = time(NULL);-極端情況下在擷取當前系統時間後系統時間馬上被修訂
PTHREAD_TASK_DBG(LOGS_DEBUG, "now time:%d\n", tv.tv_sec);
tv.tv_sec += 30;-這裡設定30秒後沒收到事件逾時返回
ret = pthread_cond_timedwait(&(pthread_info.cleanup_queue_wait), &(pthread_info.cleanup_queue_lock), &tv);
運行如下:
從上面可以看出,使用該方式線上程進入逾時等待後,無論將系統時間改成以前後以後的時間,time(NULL)會返回當前設定後的時間,但線程都不會被觸發返回.
4. 參考資料:
http://man.chinaunix.net/unix/susv3/functions/pthread_condattr_setclock.html
http://man.chinaunix.net/unix/susv3/functions/pthread_cond_timedwait.html