二 Linux--多線程( 四 )


兩個進程都想獲得對方的鎖,造成死鎖 。
條件變量概念利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使“條件成立”(給出條件成立信號) 。為了防止競爭,條件變量的使用總是和一個互斥鎖結合在一起 。
同步: 在保證數據安全的前提下 , 讓線程能夠按照某種特定的順序訪問臨界資源 , 從而避免饑餓問題,叫做同步
為什么存在線程同步?
線程同步使得每個線程都能夠訪問臨界資源,多個線程協同高效完成某些任務 。
條件變量如何與互斥鎖結合使用?
條件變量是包含一個等待隊列的 。多個線程可以去競爭一把鎖 , 沒有得到鎖資源的線程會在鎖上繼續掛起等待,當擁有鎖的線程條件變量滿足時 , 會先釋放鎖資源,然后進入到條件變量的等待隊列去等待(等待其他線程喚醒),這樣其他線程就可以獲得鎖資源,如果此時喚醒的條件變量滿足,該線程可以去喚醒等待隊列中的第一個線程,自己釋放鎖資源 , 然后讓第一個線程重新擁有鎖資源,依次如此 , 多個線程就是順序地執行工作 。這樣就可以實現線程同步的操作 。
與互斥鎖不同的是,條件變量是用來等待而不是用來上鎖的,條件變量本身就不是鎖!
條件變量用來自動阻塞一個線程,直到某種特殊情況發生為止,通常和互斥鎖一起使用 。
條件變量的兩個動作:

  • 條件不滿 , 阻塞線程
  • 條件滿足,通知阻塞的線程開始工作
條件變量的類型:pthread_cond_t
條件變量的接口條件變量是一個類型為pthread_cond_t的條件變量,課通過定義變量的方式來定義一個條件變量
  • 條件變量初始化
int pthread_cond_init(pthread_cond_t *restrict cond,  const pthread_condattr_t *restrict attr);功能: 初始化一個條件變量參數: cond:指向要初始化的條件變量指針 attr:條件變量屬性,通常為默認值 , 傳入NULL即可  也可以使用靜態初始化的方法 , 初始化條件變量:pthread_cond_t cond = PTHREAD_COND_INITIALIZER返回值: 成功:0 失?。悍?錯誤號
  • 條件變量的銷毀
int pthread_cond_destroy(pthread_cond_t *cond);功能: 銷毀一個條件變量參數: cond:指向要始化的條件變量指針返回值: 成功:0 失?。悍?錯誤號
  • 等待條件變量滿足
int pthread_cond_wait(pthread_cond_t *restrict  cond,pthread_mutex_t *restrict mutex);功能: 阻塞等待一個條件變量 a)阻塞等待條件變量cond(參1)滿足 b)釋放已掌握的互斥鎖(解鎖互斥量)相當于pthread_mutex_unlock(&mutex);a)b)兩步為一個原子操作 c)當被喚醒 , pthread_cond_wait函數返回時,解除阻塞并重新申請獲取互斥鎖pthread_mutex_lock(&mutex);參數: cond:指向要初始化的條件變量指針 mutex:互斥鎖返回值: 成功:0 失?。悍?錯誤號為什么pthread_cond_wait需要互斥量?
條件變量是實現線程同步的一種手段,如果一個線程進入等待隊列還不釋放鎖資源,這樣其他線程也不能夠得到鎖資源,這樣喚醒線程的條件變量永遠不可能滿足,那么這個線程也將一直等待下去 。所以一個線程進入等待隊列需要釋放自己手中的鎖資源來實現真正地同步
  • 喚醒條件變量
int pthread_cond_signal(pthread_cond_t *cond)功能: 喚醒阻塞隊列上的第一個線程參數: cond指向要初始化的條件變量指針返回值: 成功:0 失?。悍?錯誤號int pthread_cond_broadcast(pthread_cond_t *cond)功能: 喚醒全部阻塞在條件變量上的線程參數: cond:指向要初始化的條件變量指針返回值: 成功:0 失敗:非0錯誤號后者是喚醒等待隊列中所有的線程,而前者只喚醒等待隊列中的第一個線程 。后者會帶來一個很不好的效應——驚群效應 。多個線程同時被喚醒,但是最終只有一個線程能夠獲得“控制權”,其他獲得控制權失敗的線程可能重新進入休眠狀態 。等待獲得控制權的線程釋放鎖資源后去通知下一個線程,這樣就容易引起OS和CPU的管理調度負擔,所以不建議使用 。實例演示: 創建五個線程 , 四個線程執行run1,上來就在條件變量下等待,另一個線程執行run2,然后無腦喚醒等待隊列下的線程

推薦閱讀