深入理解pthread_cond_wait、pthread_cond_signal

===============================man pthread_cond_wait的解釋==========================

LINUX環境下多線程編程肯定會遇到需要條件變量的情況,此時必然要使用pthread_cond_wait()函數。但這個函數的執行過程比較難于理解。
??? pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE為例):
?????? Consider two shared variables x and y, protected by the mutex mut, and a condition vari-
?????? able cond that is to be signaled whenever x becomes greater than y.

????????????? int x,y;
????????????? pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
????????????? pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

?????? Waiting until x is greater than y is performed as follows:

????????????? pthread_mutex_lock(&mut);
????????????? while (x <= y) {
????????????????????? pthread_cond_wait(&cond, &mut);
????????????? }
????????????? /* operate on x and y */
????????????? pthread_mutex_unlock(&mut);

?????? Modifications on x and y that may cause x to become greater than y should signal the con-
?????? dition if needed:

????????????? pthread_mutex_lock(&mut);
????????????? /* modify x and y */
????????????? if (x > y) pthread_cond_broadcast(&cond);
????????????? pthread_mutex_unlock(&mut);

?????這個例子的意思是,兩個線程要修改X和 Y的值,第一個線程當X<=Y時就掛起,直到X>Y時才繼續執行(由第二個線程可能會修改X,Y的值,當X>Y時喚醒第一個線程),即 首先初始化一個普通互斥量mut和一個條件變量cond。之后分別在兩個線程中分別執行如下函數體:

?????????????? pthread_mutex_lock(&mut);
????????????? while (x <= y) {
????????????????????? pthread_cond_wait(&cond, &mut);
????????????? }
????????????? /* operate on x and y */
????????????? pthread_mutex_unlock(&mut);

和:???????pthread_mutex_lock(&mut);
????????????? /* modify x and y */
????????????? if (x > y) pthread_cond_signal(&cond);
????????????? pthread_mutex_unlock(&mut);
?
??? 其實函數的執行過程非常簡單,在第一個線程執行到pthread_cond_wait(&cond,&mut)時,此時如果X<=Y,則此函數就將mut互斥量解鎖?,再將cond條件變量加鎖?,此時第一個線程掛起?(不占用任何CPU周期)。
??? 而在第二個線程中,本來因為mut被第一個線程鎖住而阻塞,此時因為mut已經釋放,所以可以獲得鎖mut,并且進行修改X和Y的值,在修改之后,一個IF語句判定是不是X>Y,如果是,則此時pthread_cond_signal()函數會喚醒第一個線程?,并在下一句中釋放互斥量mut。然后第一個線程開始從pthread_cond_wait()執行,首先要再次鎖mut?, 如果鎖成功,再進行條件的判斷?(至于為什么用WHILE,即在被喚醒之后還要再判斷,后面有原因分析),如果滿足條件,則被喚醒?進行處理,最后釋放互斥量mut?。

??? 至于為什么在被喚醒之后還要再次進行條件判斷(即為什么要使用while循環來判斷條件),是因為可能有“驚群效應”。有人覺得此處既然是被喚醒的,肯定 是滿足條件了,其實不然。如果是多個線程都在等待這個條件,而同時只能有一個線程進行處理,此時就必須要再次條件判斷,以使只有一個線程進入臨界區處理。 對此,轉來一段:

引用下POSIX的RATIONALE:?

Condition Wait Semantics?

It is important to note that when pthread_cond_wait() and pthread_cond_timedwait() return without error, the associated predicate may still be false. Similarly, when pthread_cond_timedwait() returns with the timeout error, the associated predicate may be true due to an unavoidable race between the expiration of the timeout and the predicate state change.?

The application needs to recheck the predicate on any return because it cannot be sure there is another thread waiting on the thread to handle the signal, and if there is not then the signal is lost. The burden is on the application to check the predicate.?

Some implementations, particularly on a multi-processor, may sometimes cause multiple threads to wake up when the condition variable is signaled simultaneously on different processors.?

In general, whenever a condition wait returns, the thread has to re-evaluate the predicate associated with the condition wait to determine whether it can safely proceed, should wait again, or should declare a timeout. A return from the wait does not imply that the associated predicate is either true or false.?

It is thus recommended that a condition wait be enclosed in the equivalent of a "while loop" that checks the predicate.?

從上文可以看出:?
1,pthread_cond_signal在多處理器上可能同時喚醒多個線程,當你只能讓一個線程處理某個任務時,其它被喚醒的線程就需要繼續 wait,while循環的意義就體現在這里了,而且規范要求pthread_cond_signal至少喚醒一個pthread_cond_wait上 的線程,其實有些實現為了簡單在單處理器上也會喚醒多個線程.?
2,某些應用,如線程池,pthread_cond_broadcast喚醒全部線程,但我們通常只需要一部分線程去做執行任務,所以其它的線程需要繼續wait.所以強烈推薦此處使用while循環.

?????? 其實說白了很簡單,就是pthread_cond_signal()也可能喚醒多個線程,而如果你同時只允許一個線程訪問的話,就必須要使用while來進行條件判斷,以保證臨界區內只有一個線程在處理。

pthread_cond_wait()??用于阻塞當前線程,等待別的線程使用?pthread_cond_signal()?pthread_cond_broadcast來喚醒它???pthread_cond_wait()???必須與pthread_mutex 配套使用。pthread_cond_wait()?函數一進入wait狀態就會自動release mutex。當其他線程通過?pthread_cond_signal()?pthread_cond_broadcast?,把該線程喚醒,使?pthread_cond_wait()通過(返回)時,該線程又自動獲得該mutex?
????????pthread_cond_signal?函數的作用是發送一個信號給另外一個正在處于阻塞等待狀態的線程,使其脫離阻塞狀態,繼續執行.如果沒有線程處在阻塞等待狀態,pthread_cond_signal也會成功返回。
????????使用pthread_cond_signal一般不會有“驚群現象”產生,他最多只給一個線程發信號。假如有多個線程正在阻塞等待著這個條件變量的話,那么是根據各等待線程優先級的高低確定哪個線程接收到信號開始繼續執行。如果各線程優先級相同,則根據等待時間的長短來確定哪個線程獲得信號。但無論如何一個pthread_cond_signal調用最多發信一次。
????????但是?pthread_cond_signal?在多處理器上可能同時喚醒多個線程,當你只能讓一個線程處理某個任務時,其它被喚醒的線程就需要繼續 wait,

==============================另一篇很好的文章===========================

POSIX線程詳解

==============================使用效率問題============================

pthread_cond_signal函數的作用是發送一個信號給另外一個正在處于阻塞等待狀態的線程,使其脫離阻塞狀態,繼續執行.如果沒有線程處在阻塞等待狀態,pthread_cond_signal也會成功返回。
但使用pthread_cond_signal不會有“驚群現象”產生,他最多只給一個線程發信號。假如有多個線程正在阻塞等待著這個條件變量的話,那么是根據各等待線程優先級的高低確定哪個線程接收到信號開始繼續執行。如果各線程優先級相同,則根據等待時間的長短來確定哪個線程獲得信號。但無論如何一個pthread_cond_signal調用最多發信一次。
另外,互斥量的作用一般是用于對某個資源進行互斥性的存取,很多時候是用來保證操作是一個原子性的操作,是不可中斷的
用法:
pthread_cond_wait必須放在pthread_mutex_lock和pthread_mutex_unlock之間,因為他要根據共享變量的狀態來決定是否要等待,而為了不永遠等待下去所以必須要在lock/unlock隊中
共享變量的狀態改變必須遵守lock/unlock的規則
pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之間,也可以放在pthread_mutex_lock和pthread_mutex_unlock之后,但是各有各缺點。
之間:
pthread_mutex_lock
xxxxxxx
pthread_cond_signal
pthread_mutex_unlock
缺點:在某下線程的實現中,會造成等待線程從內核中喚醒(由于cond_signal)然后又回到內核空間(因為cond_wait返回后會有原子加鎖的行為),所以一來一回會有性能的問題。
在code review中,我會發現很多人喜歡在pthread_mutex_lock()和pthread_mutex_unlock(()之間調用 pthread_cond_signal或者pthread_cond_broadcast函數,從邏輯上來說,這種使用方法是完全正確的。但是在多線程環境中,這種使用方法可能是低效的。posix1標準說,pthread_cond_signal與pthread_cond_broadcast無需考慮調用線程是否是mutex的擁有者,也就是說,可以在lock與unlock以外的區域調用。如果我們對調用行為不關心,那么請在lock區域之外調用吧。這里舉個例子:
???????
我們假設系統中有線程1和線程2,他們都想獲取mutex后處理共享數據,再釋放mutex。請看這種序列:
???????
1)線程1獲取mutex,在進行數據處理的時候,線程2也想獲取mutex,但是此時被線程1所占用,線程2進入休眠,等待mutex被釋放。
???????
2)線程1做完數據處理后,調用pthread_cond_signal()喚醒等待隊列中某個線程,在本例中也就是線程2。線程1在調用pthread_mutex_unlock()前,因為系統調度的原因,線程2獲取使用CPU的權利,那么它就想要開始處理數據,但是在開始處理之前,mutex必須被獲取,很遺憾,線程1正在使用mutex,所以線程2被迫再次進入休眠。
???????
3)然后就是線程1執行pthread_mutex_unlock()后,線程2方能被再次喚醒。
?????? 從這里看,使用的效率是比較低的,如果再多線程環境中,這種情況頻繁發生的話,是一件比較痛苦的事情。
但是在LinuxThreads或者NPTL里面,就不會有這個問題,因為在Linux 線程中,有兩個隊列,分別是cond_wait隊列和mutex_lock隊列, cond_signal只是讓線程從cond_wait隊列移到mutex_lock隊列,而不用返回到用戶空間,不會有性能的損耗。
所以在Linux中推薦使用這種模式。
之后:
pthread_mutex_lock
xxxxxxx
pthread_mutex_unlock
pthread_cond_signal
優點:不會出現之前說的那個潛在的性能損耗,因為在signal之前就已經釋放鎖了
缺點:如果unlock和signal之前,有個低優先級的線程正在mutex上等待的話,那么這個低優先級的線程就會搶占高優先級的線程(cond_wait的線程),而這在上面的放中間的模式下是不會出現的。
所以,在Linux下最好pthread_cond_signal放中間,但從編程規則上說,其他兩種都可以

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252952.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252952.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252952.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LeetCode算法題-Factorial Trailing Zeroes(Java實現)

這是悅樂書的第183次更新&#xff0c;第185篇原創 01 看題和準備 今天介紹的是LeetCode算法題中Easy級別的第42題&#xff08;順位題號是172&#xff09;。給定一個整數n&#xff0c;返回n&#xff01;中的尾隨零數。例如&#xff1a; 輸入&#xff1a;3 輸出&#xff1a;0 說明…

JavaWeb基礎—JS學習小結

JavaScript是一種運行在瀏覽器中的解釋型的編程語言 推薦&#xff1a;菜鳥教程一、簡介js:javascript是基于對象【哪些基本對象呢】和和事件驅動【哪些主要事件呢】的語言&#xff0c;應用在客戶端&#xff08;注意與面向對象的區分&#xff09; js的三大特點&#xff1a;  交…

Asp.Net 設計模式 之 “簡單工廠”模式

主要思想&#xff1a;public static Operation CreateFactory(string ope) { //實例化空父類&#xff0c;讓父類指向子類 Operation op null; switch (ope) { case "": op …

UBuntu國內鏡像地址下載

http://www.oschina.net/p/ubuntu http://releases.ubuntu.com/ http://mirrors.163.com/ubuntu-releases/14.04/

Effective_STL 學習筆記(十九) 了解相等和等價的區別

find 算法和 set 的 insert 成員函數是很多必須判斷兩個值是否相同的函數代表&#xff0c; find 對 “相同” 的定義是相等&#xff0c;基于 operator &#xff0c; set::insert 對 “相同” 的定義是等價&#xff0c;通常基于 operator< 。 操作上來說&#xff0c;相等的概…

判斷是否獲取到手機相機權限

實際運用場景&#xff1a; 上傳圖片&#xff0c;查看相機設備&#xff0c;使用相機 在做這些操作的時候先調用這段話 AVAuthorizationStatus authStatus [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (authStatus AVAuthorizationStatusRestric…

事物筆記

什么是事務&#xff1a; 一件事情有N個組成單元&#xff0c;執行之后要么同時成功&#xff0c;要么同時失敗。 MySQL是一條默認的事務&#xff0c;一條sql語句就是一條事務。------------------------------------------------------------MySQL事務&#xff1a; 1、開啟一個事…

Python Socket通信黏包問題分析及解決方法

參考&#xff1a;http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 1.黏包的表現(以客戶端遠程操作服務端命令為例) 注&#xff1a;只有在TCP協議通信的情況下&#xff0c;才會產生黏包問題 基于TCP協議實現的黏包 #!/usr/bin/env python # -*- coding: utf-8 -*- …

Django 路由

定義&#xff1a; URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表&#xff1b;你就是以這種方式告訴Django&#xff0c;對于這個URL調用這段代碼&#xff0c;對于那個URL調用那段代碼。 URL配置格式&#xff1a; urlpatter…

Ubuntu默認不進入圖形界面

修改 /etc/X11/default-display-manager如果值為/usr/sbin/gdm&#xff0c;(ubuntu12.04 為/usr/sbin/lightdm)則進入圖形界面 如果值為false&#xff0c;則進入控制臺&#xff08;命令行方式&#xff09;。如果想從控制臺進入圖形界面&#xff0c;可以在控制臺上輸入命令 sudo…

讀《構建之法》的心得體會

前段時間&#xff0c;我看了《構建之法》的一些內容&#xff0c;有了一些心得體會。 軟件工程所討論的是代碼量巨大、涉及人數眾多、項目需求多變時所要解決的問題。而在校學生根本就沒有這樣的環境。而鄒欣老師的《構建之法》是我讀過的書中最淺顯易懂的軟件工程書。 在緒論中…

2440內存管理

title: 2440內存管理 tags: ARM date: 2018-10-17 19:08:49 --- 2440內存管理 特性 大/小端&#xff08;通過軟件選擇&#xff09;地址空間&#xff1a;每個 Bank 有 128M 字節(總共 1G/8 個 Bank)除了 BANK0&#xff08;16/32 位&#xff09;之外【引導ROM&#xff0c;其總線寬…

C#設計模式之十二代理模式(Proxy Pattern)【結構型】

一、引言 今天我們要講【結構型】設計模式的第七個模式&#xff0c;也是“結構型”設計模式中的最后一個模式&#xff0c;該模式是【代理模式】&#xff0c;英文名稱是&#xff1a;Proxy Pattern。還是老套路&#xff0c;先從名字上來看看。“代理”可以理解為“代替”&#…

IPv6檢測

1&#xff09;判斷服務器是否支持IPv6 &#xff1a; http://ipv6-test.com/validate.php 2&#xff09;檢測當前設備打開網站的連接方式是IPv4還是IPv6&#xff1a; http://ipv6.sjtu.edu.cn/ 轉載于:https://www.cnblogs.com/superbobo/p/6687605.html

百度首席科學家吳恩達宣布將從百度離職

海外網3月22日電 據媒體消息&#xff0c;百度首席科學家吳恩達&#xff08;Andrew Ng&#xff09;在英文自媒體平臺Medium及微博、Twitter等個人社交平臺發布公開信&#xff0c;宣布自己將從百度離職&#xff0c;開啟自己在人工智能領域的新篇章。 吳恩達是人工智能和機器學習…

CentOS7.5 使用二進制程序部署Kubernetes1.12.2(三)

一、安裝方式介紹 1、yum 安裝 目前CentOS官方已經把Kubernetes源放入到自己的默認 extras 倉庫里面&#xff0c;使用 yum 安裝&#xff0c;好處是簡單&#xff0c;壞處也很明顯&#xff0c;需要官方更新 yum 源才能獲得最新版本的軟件&#xff0c;而所有軟件的依賴又不能自己指…

Oracle存儲過程--案例

限額控制 CREATE OR REPLACE PACKAGE BODY NP_PCKG_MERCHANT_LIMIT ASPROCEDURE CHECK_LIMIT (in_iplCode IN VARCHAR2, --行業編號in_iplState IN VARCHAR2, --卡類型in_posNo IN VARCHAR2, --商戶號in_tranAmt IN …

SpringMVC—對Ajax的處理(含 JSON 類型)(2)

這里編寫了一個通用的類型轉換器&#xff1a;用來轉換形如&#xff1a; firstNamejack&lastNamelily&gender1&foodsSteak&foodsPizza&quoteEnteryourfavoritequote!&educationJr.High&tOfDDay 到 Student 對象。/*** author solverpeng* create 20…

馬來西亞熱情擁抱阿里巴巴 馬云倡議的eWTP首次落地海外

摘要&#xff1a;3月22日&#xff0c;馬來西亞總理納吉布與阿里巴巴集團董事局主席馬云一同出現在吉隆坡一場盛大啟動儀式上&#xff0c;他們將共同見證馬云的eWTP理念落地馬來西亞。 3月22日&#xff0c;在邀請阿里巴巴集團董事局主席馬云、阿里巴巴集團CEO張勇、螞蟻金服集團…

征名公布|Qtum量子鏈企業版—Unita 中文名征集圓滿落幕

Qtum量子鏈基金會為感謝社區與為了充分調動社區積極性&#xff0c;調動社區力量&#xff0c;在Qtum企業版完整公布之前將中文名留給社區成員們集思廣益&#xff0c;其中截止2018年11月26日&#xff0c;我們征集到數百份來自社區的優秀名稱&#xff0c;在經過基金會層層嚴肅認真…