1. 程式人生 > >18.執行緒同步:條件變數cond

18.執行緒同步:條件變數cond

1.條件變數

1.條件變數(Condtion Variable)是在多執行緒程式中用來實現“等待->喚醒”邏輯常用的方法。
2.條件變數+互斥鎖(一起使用)
	執行緒同步——互斥鎖
	阻塞執行緒——條件變數

2.條件變數使用場景舉例

  舉個簡單的例子,應用程式A中包含兩個執行緒t1和t2。t1需要在 bool變數test_cond為true時
才能繼續執行,而test_cond的值是由t2來改變的,這種情況下,如何來寫程式呢?可供選
擇的方案有兩 種:
  第一種是t1定時的去輪詢變數test_cond,如果test_cond為false,則繼續休眠;如果test_cond為
 true,則開始執行。
  第二種就是上面提到的條件變數,t1在test_cond為false時呼叫cond_wait進行等待,t2在改變
test_cond的值後,呼叫cond_signal,喚醒在等待中的t1,告訴t1 test_cond的值變了,這樣t1便可
繼續往下執行。
[效能對比分析]
  很明顯,上面兩種方案中,第二種方案是比較優的。在第一種方案中,在每次輪詢時,如果t1休
眠的時間比較短,會導致cpu浪費很厲害;如果t1休眠的時間 比較長,又會導致應用邏輯處理不夠
及時,致使應用程式效能下降。第二種方案就是為了解決輪詢的弊端而生的。

3.相關函式

pthread_cond_t cond; //條件變數型別

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); //初始化
int pthread_cond_destroy(pthread_cond_t *cond); //銷燬

//當條件不到來時,僅僅只阻塞一定的時長
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex,
              const struct timespec *restrict abstime);
//當條件不到來時,一直阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex);

//喚醒[至少一個]阻塞在條件變數上等待的執行緒
int pthread_cond_signal(pthread_cond_t *cond);
//廣播:喚醒[全部]的阻塞在條件變數上等待的執行緒
int pthread_cond_broadcast(pthread_cond_t *cond); 

註解:pthread_cond_wait 函式剖析

pthread_cond_wait的內部執行原理:
  [1]先對mutex解鎖,解鎖後再阻塞,一直等待條件到來; //條件沒到來時,程式阻塞在pthread_cond_wait處
  [2]當條件到來(被pthread_cond_signal喚醒)時,解除阻塞,與此同時,
pthread_cond_wait再對mutex加鎖;之後執行條件滿足的操作  
問題:pthread_cond_wait為什麼要對mutex解鎖?
   (1)使得其他執行緒有機會進入臨界區,等待相同的條件
   (2)使得其他執行緒有機會進入臨界區,對臨界資源進行更改

4.使用條件變數的萬能公式

執行緒A(等待條件的執行緒) 
	pthread_mutex_lock(mutex)         
	while(條件不滿足){
	    pthread_cond_wait(&cond);
	} 
	執行條件滿足的操作  
	pthread_mutex_unlock(mutex)
----------------------------------------  
執行緒B(修改條件的執行緒)
	pthread_mutex_lock(mutex)           
	修改條件
	pthread_mutex_unlock(&mutex);  
	if(條件滿足){
		pthread_cond_signal(&cond)
	}

疑問:為什麼等待條件的執行緒的程式碼中使用while,而不是if
      防止被虛假的喚醒,當是虛假的喚醒操作時,由於使用的while,因此需要再判斷一次,
條件不滿足時,繼續阻塞。