條件變數本身不是鎖!但它也可以造成執行緒阻塞。通常與互斥鎖配合使用。給多執行緒提供乙個會合的場所(共享的資料)。主要應用函式:
pthread_cond_init函式 pthread_cond_destroy函式
pthread_cond_wait函式 pthread_cond_timedwait函式
pthread_cond_signal函式 pthread_cond_broadcast函式
以上6 個函式的返回值都是:成功返回0, 失敗直接返回錯誤號。
pthread_cond_t型別 用於定義條件變數 pthread_cond_t cond;
引入條件變數的目的:在使用互斥鎖的基礎上引入條件變數可以使程式的效率更高,因為條件變數的引入明顯減少了執行緒取競爭互斥鎖的次數。執行pthread_cond_wait或pthread_cond_timedwait函式的執行緒明顯知道了條件不滿足,要因此在其釋放鎖之後就沒有必要再跟其它執行緒去競爭鎖了,只需要阻塞等待signal或broadcast函式將其喚醒。這樣提高了效率。
(1)pthread_cond_init函式
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
作用:初始化乙個條件變數
參2:attr表條件變數屬性,通常為預設值,傳null即可。也可以使用靜態初始化的方法,初始化條件變數:pthread_cond_t cond = pthread_cond_initializer;
(2)pthread_cond_destroy函式
int pthread_cond_destroy(pthread_cond_t *cond);
作用:銷毀乙個條件變數
(3)pthread_cond_wait函式
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
作用:阻塞等待條件變數cond(形參1)滿足條件,且釋放已經掌握的互斥鎖(解鎖互斥量)相當於pthread_mutex_unlock(&mutex)(注意這是乙個原子操作,即阻塞等待的同時馬上解鎖,類似sigsuspend函式);當被喚醒(signal或broadcast函式),pthread_cond_wait函式返回,解除阻塞並重新申請獲取互斥鎖:pthread_mutex_lock(&mutex);
(4)pthread_cond_timedwait函式
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
作用:與pthread_cond_wait函式作用相同,但其限時等待乙個條件變數,即如果在規定的時間點(第三個形參)還未被喚醒時,該執行緒自動喚醒並解除阻塞重新申請獲取互斥鎖:pthread_mutex_lock(&mutex);
引數3:struct timespec結構體。
struct timespec ; pthread_cond_timedwait (&cond, &mutex, &t); 只能定時到 2023年1月1日 00:00:01秒(早已經過去)。 2023年1月1日 00:00:00秒作為計時元年。正確用法:
time_t cur = time(null); //獲取當前時間(絕對時間)
struct timespec t; //定義timespec 結構體變數t
t.tv_sec = cur+1; //定時1秒
pthread_cond_timedwait (&cond, &mutex, &t); 傳參 參考apue.11.6執行緒同步條件變數小節
在講解setitimer函式時我們還提到另外一種時間型別:
struct timeval ;
struct production *head = null; //定義全域性指標head
struct production *rer = null; //定義全域性指標rer
pthread_mutex_t mutex = pthread_mutex_initializer; //靜態初始化
pthread_cond_t cond = pthread_cond_initializer; //靜態初始化
void *productor( void *arg ) //生產者
return null;}
void *consumer( void *arg ) //消費者
return null;}
int main( void )
ret = pthread_create( &cid, null, consumer, null);
if( ret != 0)
ret = pthread_join(pid,null);
if( ret != 0)
ret = pthread_join(cid,null);
if( ret != 0)
pthread_cond_destroy(&cond); //銷毀條件變數
pthread_mutex_destroy(&mutex); //銷毀互斥鎖
return 0;
}[root@localhost 02_pthread_sync_test]# ./pthrd_cond
--------the production is 257.
++++++++the consumer is 257.
--------the production is 324.
--------the production is 327.
++++++++the consumer is 327.
--------the production is 180.
--------the production is 313.
++++++++the consumer is 313.
--------the production is 285.
++++++++the consumer is 285.
++++++++the consumer is 180.
++++++++the consumer is 324.
--------the production is 21.
--------the production is 351.
++++++++the consumer is 351.
分析:將生產者與消費者共享的資源(產品)用鍊錶這種資料結構表示,head始終指向煉表表頭,rer用於向鍊錶中增加或刪除元素時的中間過渡。注意:這裡的head與rer都是全域性指標,都會被所有的消費者和生產者執行緒所共享,因此訪問這兩個資源時,都必須採用互斥鎖,即先加鎖,再訪問,最後解鎖。否則容易出現段錯誤。
這個程式只是建立了乙個生產者執行緒和乙個消費者執行緒,但是考慮的時候應該考慮有多個生產者執行緒和多個消費者執行緒。每乙個執行緒都是採用互斥鎖訪問共享資源head和rer。通過採用條件變數把執行緒阻塞原因分為三部分:1.生產者因為加鎖時(鎖未解鎖)而阻塞;2.消費者因為加鎖時(鎖未解鎖)而阻塞;3.消費者因為執行了wait而阻塞(這是因為條件不滿足)。這三部分執行緒,每當有鎖解鎖時,只有前兩部分執行緒會去競爭,而第三部分執行緒只有等待被喚醒後才會去競爭。因此採用條件變數可以減少互斥鎖的競爭次數。
上述程式中之所以必須採用while,是因為當因為wait阻塞而喚醒的執行緒,即使搶到了鎖,公共資源也可能被其餘消費者消耗了(因為生產者在signal之前會解鎖,而解鎖會引發消費者再次競爭鎖),因此必須再次判斷共享資源是否為空。
這道題目如果對共享資源的最大數量有限制,那麼生產者執行緒也要引入條件變數。
相較於mutex而言,條件變數可以減少競爭。如直接使用mutex,除了生產者、消費者之間要競爭互斥量以外,消費者之間也需要競爭互斥量,但如果匯聚(鍊錶)中沒有資料,消費者之間競爭互斥鎖是無意義的。有了條件變數機制以後,只有生產者完成生產,才會引起消費者之間的競爭。提高了程式效率。
linux 執行緒 條件變數
與互斥鎖不同,條件變數是用來等待而不是用來上鎖的。條件變數用來自動阻塞乙個執行緒,直到某特殊情況發生為止。條件變數使我們可以睡眠等待某種條件出現。條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作 乙個執行緒等待 條件變數的條件成立 而掛起 另乙個執行緒使 條件成立 給出條件...
Linux執行緒同步 條件變數
執行緒間的同步還有乙個情況 程序a 需要等待乙個條件成立,才執行,當條件不成立時就阻塞等待 程序b 需要設定條件,當條件成立時,喚醒程序a.這裡我們就可以用到條件變數。條件變數變數也是出自posix執行緒標準,另一種執行緒同步機制,主要用來等待某個條件的發生,然後進行相應的操作,這樣可以消除多執行緒...
linux程式設計 執行緒 條件變數
條件變數通訊機制 基本原理 初始化條件變數 int pthread cond init pthread cond t restrict cond,const pthread condattr t restrict attr pthread cond t cond pthread cond initi...