linux線程同步(2)-條件變量

https://www.cnblogs.com/yuuyuu/p/5140875.html

linux線程同步(2)-條件變量

一.概述 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

上一篇,介紹了互斥量。條件變量與互斥量不同,互斥量是防止多線程同時訪問共享的互斥變量來保護臨界區。條件變量是多線程間可以通過它來告知其他線程某個狀態發生了改變,讓等待在這個條件變量的線程繼續執行。通俗一點來講:設置一個條件變量讓線程1等待在一個臨界區的前面,當其他線程給這個變量執行通知操作時,線程1才會被喚醒,繼續向下執行。

條件變量總是和互斥量一起使用,互斥量保護著條件變量,防止多個線程對條件變量產生競爭。等會寫個小例子,看它們如何一起合作!

二.函數接口 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

1.初始化條件變量

1.1:宏常量初始化

1 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

1.2:函數初始化

1 #include <pthread.h>
2 
3 int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

跟互斥量類似,cond是條件變量的結構指針,attr是條件變量屬性的結構指針。

2.等待和通知條件變量

復制代碼
1 #include <pthread.h>
2 
3 int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
4 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
5 
6 int pthread_cond_broadcast(pthread_cond_t *cond);
7 int pthread_cond_signal(pthread_cond_t *cond);
復制代碼

等待函數里面,要傳入一個互斥量。pthread_cond_timewait()可以指定一個時間來等待,如果規定的時間沒有獲得通知,就返回ETIMEDOUT錯誤。而pthread_cond_wait()會一直阻塞

通知函數,pthread_cond_signal()至少喚醒一個等待的線程,pthread_cond_broadcast()會喚醒在該條件變量上所有線程。

3.銷毀條件變量

1 #include <pthread.h>
2 
3 int pthread_cond_destroy(pthread_cond_t *cond);

三.簡單的例子 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

我們還是用上一篇互斥量的例子。單獨使用互斥量時,有些線程要獲取某個狀態的成立,需要多次進出臨界區,對互斥量頻繁加鎖解鎖造成系統資源的浪費。下面結合條件變量來解決這個問題:

復制代碼
  1 /**
  2  * @file pthread_mutex.c
  3  */
  4 
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8 #include <unistd.h>
  9 #include <pthread.h>
 10 
 11 /* 定義互斥量 */
 12 pthread_mutex_t mtx;
 13 /* 互斥量屬性 */
 14 pthread_mutexattr_t mtx_attr;
 15 /* 全局資源 */
 16 int money;
 17 
 18 /* 條件變量 */
 19 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 20 
 21 void err_exit(const char *err_msg)
 22 {
 23     printf("error:%s\n", err_msg);
 24     exit(1);
 25 }
 26 
 27 /* 線程函數 */
 28 void *thread_fun(void *arg)
 29 {
 30     while (1)
 31     {
 32         /* 加鎖 */
 33         pthread_mutex_lock(&mtx);
 34 
 35         /* 條件變量 */
 36         while (money > 0)
 37         {
 38             printf("子線程坐等money等于0...\n");
 39             pthread_cond_wait(&cond, &mtx);
 40         }
 41 
 42         printf("子線程進入臨界區查看money\n");
 43         if (money == 0)
 44         {
 45             money += 200;
 46             printf("子線程:money = %d\n", money);
 47         }
 48 
 49         /* 解鎖 */
 50         pthread_mutex_unlock(&mtx);
 51 
 52         sleep(1);
 53     }
 54 
 55     return NULL;
 56 }
 57 
 58 int main(void)
 59 {
 60     pthread_t tid;
 61 
 62     /* 初始化互斥量屬性 */
 63     if (pthread_mutexattr_init(&mtx_attr) == -1)
 64         err_exit("pthread_mutexattr_init()");
 65 
 66     /* 設置互斥量屬性 */
 67     if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
 68         err_exit("pthread_mutexattr_settype()");
 69 
 70     /* 初始化互斥量 */
 71     if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
 72         err_exit("pthread_mutex_init()");
 73 
 74     /* 創建一個線程 */
 75     if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
 76         err_exit("pthread_create()");
 77 
 78     money = 1000;
 79     while (1)
 80     {
 81         /* 加鎖 */
 82         pthread_mutex_lock(&mtx);
 83 
 84         if (money > 0)
 85         {
 86             money -= 100;
 87             printf("主線程:money = %d\n", money);
 88         }
 89 
 90         /* 解鎖 */
 91         pthread_mutex_unlock(&mtx);
 92 
 93         /* 如果money = 1,就通知子線程 */
 94         if (money == 0)
 95         {
 96             printf("通知子線程\n");
 97             pthread_cond_signal(&cond);
 98         }
 99 
100         sleep(1);
101     }
102 
103     return 0;
104 }
復制代碼

代碼跟上一個例子幾乎一樣,就加了一個條件變量。編譯運行:

可以看到第39行的等待條件變量觸發后,子線程會一直等待,直到主線程通知它。這樣子線程就不會頻繁進入臨界區,頻繁加鎖解鎖。

四.深入知識 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

1.等待函數里面要傳入一個互斥量,這個互斥量會在這個函數調用時會發生如下變化:函數剛剛被調用時,會把這個互斥量解鎖,然后讓調用線程阻塞,解鎖后其他線程才有機會獲得這個鎖。當某個線程調用通知函數時,這個函數收到通知后,又把互斥量加鎖,然后繼續向下操作臨界區。可見這個設計是非常合理的!!!

2.條件變量的等待函數用while循環包圍,本程序的第36行。原因:如果有多個線程都在等待這個條件變量關聯的互斥量,當條件變量收到通知,它下一步就是要鎖住這個互斥量,但在這個極小的時間差里面,其他線程搶先獲取了這互斥量并進入臨界區把某個狀態改變了。此時這個條件變量應該繼續判斷別人剛剛搶先修改的狀態,即繼續執行while的判斷。還有一個原因時防止虛假通知,收到虛假通知后,只要while里面的條件為真,就繼續休眠!!!


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

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

相關文章

UVa227

【題目描述】 傳送門 【題目分析】 題目的意思很簡單&#xff0c;只是輸入輸出很毒瘤&#xff0c;我一開始用的fgets然后用scanf(" ")吃掉所有的空格和換行&#xff0c;可是這樣有可能將迷宮的空格吃掉&#xff08;例如這個空格恰好在第一行第一列&#xff09;。 …

點對點數據鏈路層

數據鏈路層的主要功能將數據轉換為相應的比特流使用的信道主要有點對點的信道方式(一對一的方式), 以及廣播的信道方式 一. 點對點信道的數據鏈路層 1. 數據鏈路和數據幀 鏈路就是從一個結點連接到相鄰結點的一段物理線路(有線或者無線), 期間不準有任何的交換結點, 因此兩臺…

UVa232

[題目描述] 傳送門 [題目分析] 簡單的模擬,注意細節 [AC代碼] #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype> #include<queue> #include<set>using namespace std;typedef long…

linux線程同步(1)-互斥量

http://www.cnblogs.com/yuuyuu/p/5140251.html 一.概述 互斥量是線程同步的一種機制&#xff0c;用來保護多線程的共享資源。同一時刻&#xff0c;只允許一個線程對臨界區進行訪問。 互斥量的工作流程&#xff1a;創建一個…

UVa1368

[題目描述] 傳送門 [題目分析] 乍一看好像有點復雜,稍微思考一下只需要找到每個位置中最多的堿基.如果相等的話優先輸出字典序小的. [AC代碼] #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<cctype>…

linux線程同步(3)-讀寫鎖

http://www.cnblogs.com/yuuyuu/p/5143881.html 一.概述 讀寫鎖與互斥量的功能類似&#xff0c;對臨界區的共享資源進行保護&#xff01;互斥量一次只讓一個線程進入臨界區&#xff0c;讀寫鎖比它有更高的并行性。讀寫鎖有…

樹的相關筆試面試題

1. 樹的創建 已知一個先序遍歷數的結果用數組表示, 其中空節點用 null_node 表示, 要求創建出這棵樹. 同樣采用遞歸的思想, 先定義一個指針, 指向數組中的第一個元素, 然后給數組的第一個結點創建相應的結點, 然后指針后移, 遞歸創建根節點的左子樹, 遞歸創建根節點的右子樹, …

UVa202

[題目描述] 傳送門 [題目分析] 就是一個模擬,不過稍微有點小復雜,而且輸出格式有點小毒瘤. 不過只是RE了兩發,PE了一發就過了,還是很開心. 需要注意數組要開很大,可能循環節出現在很后. 每個輸出樣例應該輸出一個空行,最后面也應該有,不然會PE [AC代碼] #include<cst…

linux線程同步(5)-屏障

http://www.cnblogs.com/yuuyuu/p/5152560.html 一.概述 barrier(屏障)與互斥量&#xff0c;讀寫鎖&#xff0c;自旋鎖不同&#xff0c;它不是用來保護臨界區的。相反&#xff0c;它跟條件變量一樣&#xff0c;是用來協同多…

淺談軟件測試

一. 什么是軟件測試 軟件測試是一個過程或者一系列過程, 用來測試計算機代碼完成了其應該完成的功能, 不執行不該有的操作.或者說軟件測試是根據軟件開發各階段的功能和說明而精心設計的一批測試用例, 并根據測試用例運行程序, 以發現程序錯誤的過程. 二. 軟件測試的心理學和…

UVa10340

【題目描述】 傳送門 【題目分析】 求字串&#xff0c;最好還是處理母串&#xff0c;每次找到一個子串就加1&#xff0c;這樣處理不用處理細節 【AC代碼】 #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include&l…

淺析linux下的條件變量

一.條件變量 條件變量是用來等待線程而不是上鎖的&#xff0c;條件變量通常和互斥鎖一起使用。條件變量之所以要和互斥鎖一起使用&#xff0c;主要是因為互斥鎖的一個明顯的特點就是它只有兩種狀態&#xff1a;鎖定和非鎖定&#xff0c;而條件變量可以通過允許線程阻塞和等待另…

UVa1587

【題目描述】 傳送門 【題目分析】 剛開始想簡單了&#xff0c;認為只要相對的面相等就可以了。然后發現三個不同方向的面的邊應該有相等的關系&#xff0c;即如果兩個面公用一條邊&#xff0c;那么這兩個面的另外兩條邊就是另一個面的兩條邊。而且這三個量里面肯定有一個最…

Linux多線程與同步

https://www.cnblogs.com/freedomabcd/p/7774743.html 典型的UNIX系統都支持一個進程創建多個線程(thread)。在Linux進程基礎中提到&#xff0c;Linux以進程為單位組織操作&#xff0c;Linux中的線程也都基于進程。盡管實現方式有異于其它的UNIX系統&#xff0c;但Linux的多線程…

內存管理(二)

頁面置換算法 當發生缺頁中斷的時候, 系統會在內存中選擇一個頁面將其換出內存, 而當換出內存的時候如果該頁面的內容在內存中發生修改,則必須將該新數據重新寫回到磁盤, 然后再將需要換進的數據覆蓋掉原來的數據, 而當該數據在內存中沒有被修改的時候, 此時就直接用需要換進的…

兩個棧實現一個隊列/兩個隊列實現一個棧

http://blog.csdn.net/sinat_30472685/article/details/70157227 1兩個棧實現一個隊列 1.原理分析&#xff1a; 隊列的主要操作有兩個&#xff1a;入隊操作和出隊操作&#xff0c;出隊時從隊頭出&#xff0c;入隊是從隊尾插入&#xff0c;入隊的操作和入棧的操作類似&#xff0…

UVa1588

【題目描述】 傳送門 【題目分析】 剛開始想了一會沒有想到什么很好的算法&#xff0c;看到了長度最多為100&#xff0c;就知道自己想的沒有什么意義了&#xff0c;直接暴力&#xff0c;把每一種填法都試一下就知道了。適當剪枝一下&#xff08;一個簡單的樂觀函數&#xff…

轉:C++中const、volatile、mutable的用法

const修飾普通變量和指針 const修飾變量&#xff0c;一般有兩種寫法&#xff1a; const TYPE value; TYPE const value; 這兩種寫法在本質上是一樣的。它的含義是&#xff1a;const修飾的類型為TYPE的變量value是不可變的。對于一個非指針的類型TYPE&#xff0c;無論怎么寫&…

數據鏈路

廣播信道的數據鏈路層 局域網的優點 網絡為一個單位所擁有, 地理范圍和站點數有限 局域網具有廣播特性, 可以從一個站點方便地訪問到整個網絡. 各個主機之間可以共享資源, 無論是局域網上的硬件資源還是局域網上的軟件資源 便于系統的擴展換和演化, 各個設備之間的位置可靈…

UVa11809

【題目描述】 傳送門 【題目分析】 終于把這道題做完了&#xff0c;之前一直連題意都看不懂。實在不行上網找了一下大佬的博客&#xff0c;看懂題意后自己寫&#xff0c;發現讀入很難處理&#xff0c;就又學習了一下大佬的讀入方法&#xff0c;用的是C里面的sstream&#xf…