摘要:多線程編程中,線程A循環(huán)計算,然后sleep一會接著計算(目的是減少CPU利用率);存在的問題是,如果要關(guān)閉程序,通常選擇join線程A等待線程A退出,可是我們必須等到sleep函數(shù)返回,該線程A才能正常退出,這無疑減慢了程序退出的速度。當(dāng)然,你可以terminate線程A,但這樣做很不優(yōu)雅,且會存在一些未知問題。采用pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t *mutex, const struct timespec * abstime)可以優(yōu)雅的解決該問題,設(shè)置等待條件變量cond,如果超時,則返回;如果等待到條件變量cond,也返回。本文暫不將內(nèi)部機理,僅演示一個demo。
首先,看這段代碼,thr_fn為一個線程函數(shù):
bool flag = true;void * thr_fn(void * arg) { while (flag){ printf(".\n"); sleep(10); } printf("thread exit\n");} int main() { pthread_t thread; if (0 != pthread_create(&thread, NULL, thr_fn, NULL)) { printf("error when create pthread,%d\n", errno); return 1; } char c ; while ((c = getchar()) != 'q'); printf("Now terminate the thread!\n"); flag = false; printf("Wait for thread to exit\n"); pthread_join(thread, NULL); printf("Bye\n"); return 0;}
輸入q后,需要等線程從sleep中醒來(由掛起狀態(tài)變?yōu)檫\行狀態(tài)),即最壞情況要等10s,線程才會被join。采用sleep的缺點:不能及時喚醒線程。
采用pthread_cond_timedwait函數(shù)實現(xiàn)的如下:
#include <stdio.h>#include <sys/time.h>;#include <unistd.h>;#include <pthread.h>;#include <errno.h>; pthread_t thread;pthread_cond_t cond;pthread_mutex_t mutex;bool flag = true; void * thr_fn(void * arg) { struct timeval now; struct timespec outtime; pthread_mutex_lock(&mutex); while (flag) { printf(".\n"); gettimeofday(&now, NULL); outtime.tv_sec = now.tv_sec + 5; outtime.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait(&cond, &mutex, &outtime); } pthread_mutex_unlock(&mutex); printf("thread exit\n");} int main() { pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); if (0 != pthread_create(&thread, NULL, thr_fn, NULL)) { printf("error when create pthread,%d\n", errno); return 1; } char c ; while ((c = getchar()) != 'q'); printf("Now terminate the thread!\n"); flag = false; pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); printf("Wait for thread to exit\n"); pthread_join(thread, NULL); printf("Bye\n"); return 0;}
說明(翻譯摘要中提供的連接,翻譯的不好,湊合的看吧):
pthread_cond_timedwait()函數(shù)阻塞住調(diào)用該函數(shù)的線程,等待由cond指定的條件被觸發(fā)(pthread_cond_broadcast() or pthread_cond_signal())。
當(dāng)pthread_cond_timedwait()被調(diào)用時,調(diào)用線程必須已經(jīng)鎖住了mutex。函數(shù)pthread_cond_timedwait()會對mutex進行【解鎖和執(zhí)行對條件的等待】(原子操作)。這里的原子意味著:解鎖和執(zhí)行條件的等待是原則的,一體的。(In this case, atomically means with respect to the mutex and the condition variable and other access by threads to those objects through the pthread condition variable interfaces.)
如果等待條件滿足或超時,或線程被取消,調(diào)用線程需要在線程繼續(xù)執(zhí)行前先自動鎖住mutex,如果沒有鎖住mutex,產(chǎn)生EPERM錯誤。即,該函數(shù)返回時,mutex已經(jīng)被調(diào)用線程鎖住。
等待的時間通過abstime參數(shù)(絕對系統(tǒng)時間,過了該時刻就超時)指定,超時則返回ETIMEDOUT錯誤碼。開始等待后,等待時間不受系統(tǒng)時鐘改變的影響。
盡管時間通過秒和納秒指定,系統(tǒng)時間是毫秒粒度的。需要根據(jù)調(diào)度和優(yōu)先級原因,設(shè)置的時間長度應(yīng)該比預(yù)想的時間要多或者少點。可以通過使用系統(tǒng)時鐘接口gettimeofday()獲得timeval結(jié)構(gòu)體。
注: 為了可靠的使用條件變量和確保不忘記對條件變量的喚醒操作,應(yīng)該采用一個bool變量和mutex變量同條件變量配合使用。如本文demo。