互斥鎖、條件變量

一、互斥鎖

1. 函數原型:

pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);  
pthread_mutex_destroy(pthread_mutex_t *mutex); 

分析:

  • pthread_mutex_t 類型,其本質是一個結構體,為簡化理解,應用時可忽略其實現細節,簡單當成整數看待。
  • pthread_mutex_t??mutex:變量mutex只有兩種取值0、1;

函數一參數1:傳出參數,調用時應傳&mutex

  • restrict關鍵字:只用于限制指針,告訴編譯器,所有修改該指針指向內存中內容的操作,只能通過本指針完成。不能通過除本指針以外的其他變量或指針修改。

函數一參數2:互斥屬性。是一個傳入參數,通常傳NULL,選用默認屬性(線程間共享).

  • 靜態初始化:如果互斥鎖mutex是靜態分配的(定義在全局,或加了static關鍵字修飾),可以直接使用宏進行初始化。pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 動態初始化:局部變量應采用動態初始化, pthread_mutex_init(&mutex, NULL);

?

pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_unlock(pthread_mutex_t *mutex);                                        

分析:

  • 函數1:沒有被上鎖,當前線程會將這把鎖鎖上;被鎖上了,當前線程阻塞,鎖被打開之后,線程解除阻塞(加鎖。可理解為將mutex--(或-1))。
  • 函數2:同時將阻塞在該鎖上的所有線程全部喚醒解鎖(可理解為將mtex++(或+1)).

?

2. 測試代碼:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>void *tfn(void *arg)
{srand(time(NULL));while(1) {printf("hello ");sleep(rand() % 3); //模擬長時間操作共享資源,導致cpu易主,產生與時間有關的錯誤printf("word\n");sleep(rand() % 3);}return NULL;
}int main()
{pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while(1) {printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}return 0;
}

輸出結果:

?

??3. 測試代碼:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>void *tfn(void *arg)
{srand(time(NULL));while(1) {printf("hello ");sleep(rand() % 3); //模擬長時間操作共享資源,導致cpu易主,產生與時間有關的錯誤printf("word\n");sleep(rand() % 3);}return NULL;
}int main()
{pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while(1) {printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}return 0;
}

輸出結果

?

二、 條件變量

條件變量本身不是鎖,但它也可以造成線程阻塞,通常與互斥鎖配合使用,給多線程提供一個會合的場所。

?

1. 函數原型:

pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t * attr);  //初始化一個條件變量
pthread_cond_destroy(pthread_cond_t *cond);     // 銷毀一個條件變量   pthread_cond_signal(pthread_cond_t *cond);    // 喚醒至少一個阻塞在條件變量上的線程
pthread_cond_broadcast(pthread_cond_t *cond); // 喚醒全部阻塞在條件變量上的線程                             

?

2. 函數原型:

pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

分析:

函數作用:阻塞等待一個條件變量

  1. 阻塞等待條件變量cond(參數1)滿足
  2. 釋放已掌握的互斥鎖(解鎖互斥量),相當于pthread_mutex_unlock(&mutex); {1、2兩步為一個原子操作}
  3. 當被喚醒,pthread_cond_wait函數返回,解除阻塞并重新獲取互斥鎖pthread_mutex_lock(&mutex);

?

3. 函數原型:

? ??函數作用:限時等待一個條件變量

pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,  const struct timespec *restrict abstime);

參數3:

struct timespec 
{time_t tv_sec;  seconds 秒 long tv_nsec;    nanoseconds 納秒
}

你形參:abstime:絕對時間

如:time(NULL)返回的就是絕對時間。而alarm(1)是相對時間,相當當前時間定時1秒鐘。

struct timespec t = {1,??0};

pthread_cond_time(&cond, &mutex, &t);只能定時到1970年1月1日00:00:01秒(早已經過去)

正確用法:

time_t cur = time(NULL);   獲取當前時間
struct timespec t;         定義timespec結構體變量
t.tv_sec = cur + 1;        定時一秒
pthread_cond_timewait(&cond, mutex, &t) 傳參 

?

4. 函數原型:

pthread_cond_signal(pthread_cond_t *cond);    // 喚醒至少一個阻塞在條件變量上的線程
pthread_cond_broadcast(pthread_cond_t *cond); // 喚醒全部阻塞在條件變量上的線程

?

?

三、生產者消費者條件變量模型

線程同步典型的案例即為生產者消費者模型,而借助條件變量來實現這一案例,是比較常見的方法,假定有兩個線程,一個模擬生產者行為,一個模擬消費者行為,兩個線程同時操作一個共享資源(一般稱之為匯聚),生產者向其中添加產品,消費者從中消費掉產品。

1. 測試代碼:

#include <pthread.h> 
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>struct msg
{struct msg *next;int num;
};struct msg *head;
struct msg *mp;pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;  //靜態初始化:一個條件變量和一個互斥量 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *consumer(void *p)
{for (; ;){pthread_mutex_lock(&lock);while (head == NULL)                           //頭指針為空,說明沒有節點 可以為if嗎 pthread_cond_wait(&has_product, &lock);mp = head;head = mp->next;                               //模擬消費掉一個產品pthread_mutex_unlock(&lock);printf("-consume-----%d\n", mp->num);free(mp);sleep(rand() % 5);}
}void *producer(void *p)
{for (; ;) {mp = malloc(sizeof(struct msg));mp->num = rand() % 1000 + 1;                  //模擬生產一個產品printf("-Produce----%d\n", mp->num);pthread_mutex_lock(&lock);mp->next = head;head = mp;pthread_mutex_unlock(&lock);pthread_cond_signal(&has_product);          //將等待在該條件變量上的一個線程喚醒sleep(rand() % 5);}
}int main()
{pthread_t pid, cid;srand(time(NULL));pthread_create(&pid, NULL, producer, NULL);pthread_create(&cid, NULL, consumer, NULL);pthread_join(pid, NULL);pthread_join(cid, NULL);return 0;
}

輸出結果:

?【注意】:為什么用while循環而不用if呢?

一個生產者可能對應著多個消費者,生產者向隊列中插入一條數據之后發出signal,然后各個消費者線pthread_cond_wait獲取mutex后返回,當然,這里只有一個線程獲取到了mutex,然后進行處理,其它線程會pending在這里,處理線程處理完畢之后釋放mutex,剛才等待的線程中有一個獲取mutex,如果這里用if,就會在當前隊列為空的狀態下繼續往下處理,這顯然是不合理的。

?

?

五、參考資料

1?深入解析條件變量(condition variables)
?

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

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

相關文章

Java面試你必須要知道的那些知識,深夜思考

如何提升自己的實力&#xff1f; Step 1&#xff1a;梳理自己的知識 對照下面這份學習大綱&#xff0c;梳理出自己的知識盲區&#xff0c;這份大綱里面的技術點完全對標P7崗的主流技術&#xff0c;因此這是一份很好的知識大綱筆記。 Step 2&#xff1a;查漏補缺&#xff0c;夯…

Java面試你必須要知道的那些知識,面試建議

二、面試題 面&#xff1a;考你幾個紅黑樹的知識點&#x1f980; 紅黑樹的數據結構都用在哪些場景&#xff0c;有什么好處&#xff1f;紅黑樹的時間復雜度是多少&#xff1f;紅黑樹中插入新的節點時怎么保持平衡&#xff1f; 面&#xff1a;2-3樹都是不沒看&#xff0c;回去…

存儲映射I/O(一)

一、存儲映射I/O 存儲映射I/O使一個磁盤文件與存儲空間中的一個緩沖區映射&#xff0c;于是當從緩沖區中取數據&#xff0c;就相當于讀文件中的相應字節。于此類似&#xff0c;將數據存入緩沖區&#xff0c;則相應的字節就自動寫入文件&#xff0c;這樣&#xff0c;就可在不不…

【絕對干貨】kafkastream廣告

Java如何入門&#xff1f; 1、建立好開發環境 首先建立好開發環境非常重要&#xff0c;工欲善其事&#xff0c;必先利其器。做任何開發&#xff0c;首先就是要把這個環境準備好&#xff0c;之后就可以去做各種嘗試&#xff0c;嘗試過程中就能逐漸建立信心。初學者往往在環境配…

存儲映射IO(二)

mmap父子進程間通信 1. 測試代碼&#xff1a; #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/wait.h>int var 100;int main(void) {int *p;pid_t pid;int fd;…

【聊透SpringMVC】java技術經理崗位職責

緩存維護方案一 如果是一讀&#xff08;線程B&#xff09;一寫&#xff08;線程A&#xff09;操作&#xff0c;「先操作緩存&#xff0c;再操作數據庫」。流程圖如下所示&#xff1a; 1.線程A發起一個寫操作&#xff0c;第一步del cache 2.線程A第二步寫入新數據到DB 3.線程…

【聊透SpringMVC】自學java和三大框架要多久

餓了么一面&#xff08;Java&#xff09; hashmap源碼問題 HashMap底層結構 put操作講一下 HashMap、HashMap如何保證線程安全、ConcurrentHashMap JVM有哪些回收算法&#xff0c;對應的收集器有哪些&#xff1f; jvm g1的內存模型講一下&#xff0c;G1和CMS收集器的區別&#…

【設計思想解讀開源框架】mysql官方文檔中文版下載免費

01 源碼分析 源碼閱讀&#xff0c;最核心有三點&#xff1a;技術基礎強烈的求知欲耐心。 1.1 設計模式&#xff08;45設計模式&#xff1a;介紹優缺點應用實例源代碼解決問題&#xff09; 1.2 Spring復習大綱&#xff1a;依賴注入IocBeans注解數據訪問AOPMVC等 1.3 Spring全家…

命令新參

命令形參&#xff1a; 命令行參數是使用main()函數參數來處理的&#xff0c;其中&#xff0c;argc是指傳入參數的個數&#xff0c;argv[]是一個指針數組&#xff0c;指向傳遞給程序的每個參數。 應當指出的是&#xff0c; argv[0]存儲程序的名稱&#xff0c;argv[1]是一個指向…

【金三銀四】啟動mysql服務器

微服務架構 ①微服務概念&#xff1a; ②Spring Cloud微服務架構&#xff1a; 海量數據處理 ①&#xff1a;經典的海量數據處理面試題 高可用架構 ①基于 Hystrix 實現高可用&#xff1a; ②限流&#xff1a; ③熔斷&#xff1a; 高并發架構 ①消息隊列&#xff1a; ②搜索…

函數fork vfork

一、函數fork fork函數原型&#xff1a; #include <unistd.h> pid_t fork(void); 二、程序清單 1. 測試代碼&#xff1a; #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h>…

【金三銀四】微軟java后端社招

分布式系統特性與衡量標準 透明性&#xff1a;使用分布式系統的用戶并不關心系統是怎么實現的&#xff0c;也不關心讀到的數據來自哪個節點&#xff0c;對用戶而言&#xff0c;分布式系統的最高境界是用戶根本感知不到這是一個分布式系統 可擴展性&#xff1a;分布式系統的根…

【面試必會】java虛擬機原理

如何才可以進大廠&#xff1f; 答案其實也很簡單&#xff0c;能力學歷。不知道大家有沒有發現&#xff0c;大廠的一些部門對于學歷要求已經放低了&#xff0c;阿里的一些部門同樣也招大專學歷的程序員&#xff0c;當然肯定也是因為他的能力足夠出色。 對于準備秋招的你來說&a…

函數exec

exec函數族 1. 執行指定目錄下的程序 #include <unistd.h> int execl(const char *path, const char *arg, ...);返回值&#xff1a;若出錯&#xff0c;返回-1&#xff1b;若成功&#xff0c;不返回 分析&#xff1a; path: 要執行的程序的絕對路徑變參arg: 要執行的…

【面試必備】java寫spark好不好

并發編程三大特性 原子性 一個操作或者多次操作&#xff0c;要么所有的操作全部都得到執行并且不會受到任何因素的干擾而中斷&#xff0c;要么所有的操作都執行&#xff0c;要么都不執行。 對于基本數據類型的訪問&#xff0c;讀寫都是原子性的【long和double可能例外】。 …

【面試必備】java面試題視頻講解

二、我們先來看看這份筆記到底有什么 1、先把kubernetes跑起來&#xff08;先跑起來創建kubernetes集群部署應用訪問應用Scale應用滾動更新&#xff09; 2、重要概念 3、部署kubernetes Cluster&#xff08;安裝docker安裝 kubelet.kubeadm和 kubectll用kubeadm 創建cluster&a…

【面試總結】java測試工程師培訓

阿里P8級架構師核心理論落地篇 再造淘寶&#xff0c;貫穿全系&#xff0c;阿里團隊代碼落地&#xff0c;詳細每個版本迭代&#xff0c;拒絕2-3個月PPT架構師再造淘寶之咚寶-技術支撐-完整搭建DevOps再造淘寶之咚寶-統一規則-代碼規范落地解析再造淘寶之咚寶搭建基礎服務再造淘…

進程組的應用

一、實驗1 題目&#xff1a;利用進程扇完成一個小實驗。該進程扇有 1 個父進程和 3 個子進程&#xff0c;我們希望達到圖 1 中的效果&#xff0c;即將進程 0 (父進程)和進程 1 設置成一組&#xff0c;假設為組 1&#xff0c;將進程 2 和 進程 3 設置成另一個組&#xff0c;假設…

【原理+實戰+視頻+源碼】docker映射端口教程

阿里巴巴Java崗面試題分享 1.HashMap 的內部結構&#xff1f;內部原理&#xff1f;和 HashTable 的區別&#xff0c;假如發?了 hash 碰撞&#xff0c;如何設計能讓遍歷效率?&#xff1f; 2.講一講講講 ConcurrentHashMap吧。 3.講一下JVM虛擬機內存結構&#xff0c;以及它…

前臺進程組、后臺進程組

一、前臺進程組、后臺進程組 cat | cat & cat | cat | cat 輸出結果&#xff1a; 二、主要函數應用 1. tcgetpgrp函數原型&#xff1a; #include <unistd.h> pid_t tcgetpgrp(int fd);返回值&#xff1a;若成功&#xff0c;返回前臺進程組ID, 若出錯&#xff0c;…