很顯然,pthread中的條件變量與Java中的wait,notify類似
假設有共享的資源sum,與之相關聯的mutex 是lock_s.假設每個線程對sum的操作很簡單的,與sum的狀態無關,比如只是sum++.那么只用mutex足夠了.程序員只要確保每個線程操作前,取得lock,然后sum++,再unlock即可.每個線程的代碼將像這樣add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
}
如果操作比較復雜,假設線程t0,t1,t2的操作是sum++,而線程t3則是在sum到達100的時候,打印出一條信息,並對sum清零.這種情況下,如果只用mutex, 則t3需要一個循環,每個循環里先取得lock_s,然后檢查sum的狀態,如果sum>=100,則打印並清零,然后unlock.如果sum<100,則unlock,並sleep()本線程合適的一段時間.
這個時候,t0,t1,t2的代碼不變,t3的代碼如下
print()
{
while (1)
{
pthread_mutex_lock(lock_s);
if(sum<100)
{
printf(“sum reach 100!”);
pthread_mutex_unlock(lock_s);
}
else
{
pthread_mutex_unlock(lock_s);
my_thread_sleep(100);
return OK;
}
}
}
這種辦法有兩個問題
1) sum在大多數情況下不會到達100,那么對t3的代碼來說,大多數情況下,走的是else分支,只是lock和unlock,然后sleep().這浪費了CPU處理時間.
2) 為了節省CPU處理時間,t3會在探測到sum沒到達100的時候sleep()一段時間.這樣卻又帶來另外一個問題,亦即t3響應速度下降.可能在sum到達200的時候,t3才會醒過來.
3) 這樣,程序員在設置sleep()時間的時候陷入兩難境地,設置得太短了節省不了資源,太長了又降低響應速度.真是難辦啊!
這個時候,condition variable內褲外穿,從天而降,拯救了焦頭爛額的你.
你首先定義一個condition variable.
pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;
t0,t1,t2的代碼只要后面加兩行,像這樣
add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
if(sum>=100)
pthread_cond_signal(&cond_sum_ready);
}
而t3的代碼則是
print
{
pthread_mutex_lock(lock_s);
while(sum<100)
pthread_cond_wait(&cond_sum_ready, &lock_s);
printf(“sum is over 100!”);
sum=0;
pthread_mutex_unlock(lock_s);
return OK;
}
注意兩點:
1) 在thread_cond_wait()之前,必須先lock相關聯的mutex, 因為假如目標條件未滿足,pthread_cond_wait()實際上會unlock該mutex, 然后block,在目標條件滿足后再重新lock該mutex, 然后返回.--這點非常重要
2) 為什么是while(sum<100),而不是if(sum<100) ?這是因為在pthread_cond_signal()和pthread_cond_wait()返回之間,有時間差,假設在這個時間差內,還有另外一個線程t4又把sum減少到100以下了,那么t3在pthread_cond_wait()返回之后,顯然應該再檢查一遍sum的大小.這就是用while的用意
pthread_cond_wait() 用於阻塞當前線程,等待別的線程使用pthread_cond_signal()或pthread_cond_broadcast來喚醒它。
pthread_cond_wait() 必須與pthread_mutex_lock() 配套使用。pthread_cond_wait()函數一進入wait狀態就會自動release mutex。當其他線程通過pthread_cond_signal()或pthread_cond_broadcast,把該線程喚醒,使pthread_cond_wait()通過(返回)時,該線程又自動獲得該mutex。
pthread_cond_signal()必須和pthread_mutex_unlock(lock_s) 配套使用,在發送信號或者廣播之前,一定要先unlock mutex,因為阻塞在條件變量上的線程被喚醒的時候,要對mutex加鎖,如果該線程被喚醒,而此時通知線程仍然鎖住互斥鎖,澤被喚醒線程立刻阻塞在互斥鎖上。