互斥量(互斥鎖)

一、互斥量mutex

  1. Linux提供一把互斥鎖mutex(也稱之為互斥量)
  2. 每個線程在對資源操作前都嘗試先加鎖,成功加鎖才能操作,操作結束后解鎖。
  3. 資源還是共享的,線程間也還是競爭的,但通過鎖將資源的訪問變為互斥操作,而后與時間有關的錯誤也不會在產生了。

如圖所示:

但是應該注意:同一個時刻,只能有一個線程持有該鎖。

當A線程對某個全局變量加鎖訪問,B在訪問前嘗試加鎖,拿不到鎖,B阻塞。C線程不去加鎖,而直接訪問該全局變量,依然能夠訪問,但會出現數據混亂。

所以,互斥鎖實質上是是操作系統提供的一把“建議鎖”(又稱“協同所”),建議程序中有多線程訪問共享資源的時候使用該機制,但是,并沒有強制限定。

?

二、主要應用函數

分析:

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

1. 函數原型:

功能:初始化一個互斥鎖(互斥量);\rightarrow?初值可看做1

#include<pthread.h>
pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);                                                返回值:若成功,返回0,否則,返回錯誤編號  

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

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

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

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

?

2. 函數原型:

? ? 功能:銷毀一個互斥鎖

#include<pthread.h>
pthread_mutex_destroy(pthread_mutex_t *mutex); 返回值:若成功,返回0,否則,返回錯誤編號 

?

3. 函數原型:

? ? 功能:加鎖。可理解為將mutex--(或-1)

#include<pthread.h>
pthread_mutex_lock(pthread_mutex_t *mutex);返回值:若成功,返回0,否則,返回錯誤編號

分析:

  • 沒有被上鎖,當前線程會將這把鎖鎖上
  • 被鎖上了:當前線程阻塞,鎖被打開之后,線程解除阻塞。

?

4. 函數原型:

? ?功能:解鎖。可理解為將mtex++(或+1)

#include<pthread.h>
pthread_mutex_unlock(pthread_mutex_t *mutex);返回值:若成功,返回0,否則,返回錯誤編號	

注意:

  • 同時將阻塞在該鎖上的所有線程全部喚醒

?

5. 函數原型:

功能:嘗試加鎖, 失敗返回, 不阻塞

#include<pthread.h>
pthread_mutex_trylock(pthread_mutex_t *mutex);返回值:若成功,返回0,否則,返回錯誤編號

分析:

  • 沒有鎖上:當前線程會給這把鎖加鎖
  • 如果鎖上了:不會阻塞,返回

?

三、程序清單(一)

1. 測試代碼:

#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;
}

運行結果:

?

2. 測試代碼:

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

輸出結果:

?

?

3. 測試代碼:

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

輸出結果:

四、程序清單(二)

四、加鎖與解鎖

lock與unlock:

  • lock嘗試加鎖,如果加鎖不成功,線程阻塞,阻塞到持有該互斥量的其他線程解鎖為止。
  • unlock主動解鎖,同時將阻塞到該鎖上所有線程全部喚醒,至于哪個線程先被喚醒取決于優先級,調度。默認:先阻塞、先喚醒。

例如:T1 T2 T3 T4 使用一把mutex鎖,T1加鎖成功,其他線程均阻塞,直至T1解鎖,T1解鎖后,T2 T3 T4均被喚醒,并自動再次嘗試加鎖。

可假想mutex鎖init成功初值為1。lock功能是將mutex--。unlock將mutex++。

?

lock與trylock:

  • lock加鎖失敗會阻塞,等待鎖釋放。
  • trylock加鎖失敗直接返回錯誤號(如EBUSY),不阻塞。

?

注意:在訪問共享資源前加鎖,訪問結束后立即解鎖。鎖的“粒度”越小越好。

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

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

相關文章

一眼就能看懂的Java自學手冊,終局之戰

珍藏版&#xff08;1&#xff09;——Mybatis入門 1.什么是MyBatis 2.為什么我們要用Mybatis? 3.Mybatis快速入門 3.1 導入開發包 3.2準備測試工作 3.3 創建mybatis配置文件 3.4 編寫工具類測試是否獲取到連接 3.5 創建實體與映射關系文件 3.6 編寫DAO 4.Mybatis工作…

Centos 6.x

1. centos升級gcc教程&#xff1a;鏈接 2. 虛擬機中的Centos聯通網絡&#xff1a;鏈接 3. 虛擬機安裝Centos7系統教程&#xff1a;鏈接

Java虛擬機學習集錦是我攢來的,帶你碾壓面試官!

1. 一致性&#xff08;Consistency&#xff09; 一致性&#xff08;Consistency&#xff09;是指多副本&#xff08;Replications&#xff09;問題中的數據一致性。可以分為強一致性、順序一致性與弱一致性。 1.1 強一致性&#xff08;Strict Consistency&#xff09; 也稱為…

Java虛擬機學習集錦是我攢來的,看這篇文章準沒錯!

一面 介紹一下自己 問項目經歷, 聊"數據同步" 接著聊上了 K8S 的項目 有沒有什么鉆研得比較深得技術&#xff1f;&#xff08;大佬&#xff1a;kubernetes, golang, prometheus, java&#xff09; kubernetes 的架構是怎么樣的? 這個問題很大&#xff0c;拆成 …

文件描述符、函數open和openat

文件描述符 pcb&#xff1a;結構體一個進程有一個文件描述符&#xff1a;1024文件描述符&#xff1a;尋找磁盤文件函數open和openat 函數原型&#xff1a; include<sys/stst.h> #include<fcntl.h>int open(const char *pathname, int flags); int open(const ch…

Java這些高端技術只有你還不知道,移動架構師成長路線

并發編程共享模型篇 并發編程概覽進程與線程Java線程共享模型之管程共享模型之內存共享模型之無鎖共享模型之不可變共享模型之工具 共享模型之管程 原理之 Monitor(鎖) 原理之偽共享 模式篇—正確姿勢 同步模式之保護性智停同步模式之Blking同步模式之順序控制異步模式之生產…

函數read、write、lseek

函數原型&#xff1a; #include<unistd.h> ssize_t read(int fd, void *buf, size_t count);返回值&#xff1a;讀到的字節數&#xff0c;若已到文件尾&#xff0c;返回0&#xff1b;若出錯&#xff0c;返回-1 參數&#xff1a; fd&#xff1a;函數open的返回值buf&a…

Java這些高端技術只有你還不知道,薪資翻倍

正文 我的第一份工作是在一家外企&#xff0c;當時抱著“逃離”上海的想法去了二線城市的分公司&#xff0c;但是管理文化氛圍跟總部幾乎都是一樣的&#xff0c;這份工作經歷對我后面的工作不論是做事風格、習慣上還是思考問題的方式方法上都有很大的影響。后面陸續進入國企&a…

函數dup和dup2

函數原型&#xff1a; #include<unistd.h> int dup(int oldfd);返回值&#xff1a;若成功&#xff0c;返回新的文件描述符&#xff1b;若出錯&#xff0c;返回-1 參數&#xff1a; oldfd&#xff1a;要復制的文件描述符dup調用成功&#xff1a;有兩個文件描述符指向同…

Java進階面試資料無償分享!真香系列

8-22 投遞簡歷 8-24 一面&#xff08;大概1h50min&#xff09; 0、currenthashmap怎么擴容的&#xff1f;fwn為什么固定hash -1&#xff0c;這樣設計有什么好處&#xff1f;幫助擴容是發生在什么階段?讀線程和寫線程都會幫助擴容嗎&#xff1f;擴容的時候任務具體怎么協調的&…

Java通用流行框架大全,絕對干貨

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

Java集合類中絕對占有一席之地的List,漲薪7K!

一、先來解讀&#xff1a;23種設計模式要點 1.單例模式&#xff08;Singleton Pattern&#xff09; 2.工廠模式 3.抽象工廠模式&#xff08;Abstract Factory Pattern&#xff09; 4.模板方法模式&#xff08;Template Method Pattern&#xff09; 5.建造者模式&#xff08;Bu…

Java面試10大知識點總結寶典助你通關!已拿意向書!

Java基礎 1.Java語言的三大特性 2.Java語言主要特性 3. JDK和JRE有什么區別 4.Java基本數據類型及其封裝類 5.如果main方法被聲明為private會怎樣? 6.說明- -下public static void main(String argsQ])這段聲明里每個關鍵字的作用 7.與equals的區別 8.Object有哪些公用方法 9.…

互斥鎖、條件變量

一、互斥鎖 1. 函數原型&#xff1a; pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_destroy(pthread_mutex_t *mutex); 分析&#xff1a; pthread_mutex_t 類型&#xff0c;其本質是一個結構體&#xf…

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.線程…