線程同步與互斥。(互斥量與條件變量、Posix信號量)
線程互斥:
所謂互斥:即是間接制約關系,指系統中的某些共享資源,一次只允許一個線程訪問,當一個線程正在訪問該臨界資源時,其它線程必須等待。
mutex(互斥量):
- 互斥量本身也是一把鎖,提供對資源的獨占訪問。
- 大部分情況下,線程使用的數據都是局部變量,變量的地址空間在線程棧空間內,變量歸屬于某個單個線程,其它線程無法獲得這種變量。
共享變量:很多變量需要在線程間共享,可以通過數據的共享,完成數據間的交互。
下面我們來看一個買票問題(沒加互斥量之前)
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<pthread.h>
5
6 int ticket=100;
7
8 void*thread_run(void*arg)
9 {
10 int a=(int)arg;
11 while(1){
12 if(ticket>0){
13 usleep(10000);
14 printf("%d sells ticket:%d\n",a ,ticket);
15 ticket--;
16 }else{
17 break;
18 }
19 }
20 }
21 int main()
22 {
23 pthread_t t1,t2,t3,t4;
24 void*ret1;
25 void*ret2;
26 void*ret3;
27 void*ret4;
28 pthread_create(&t1,NULL,thread_run,(void*)1);
29 pthread_create(&t2,NULL,thread_run,(void*)2);
30 pthread_create(&t3,NULL,thread_run,(void*)3);
31 pthread_create(&t4,NULL,thread_run,(void*)4);
32
33 pthread_join(t1,&ret1);
34 pthread_join(t2,&ret2);
35 pthread_join(t3,&ret3);
36 pthread_join(t4,&ret4);
37 }
結果顯示:
因為每個線程取票的過程并不是原子性的。
下面來看看互斥量的接口;
- 初始化互斥量:
- 方法一:靜態分配:
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER
- 方法二:動態分配:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
參數解釋:mutex:要初始化的互斥量。
attr:NULL
- 銷毀互斥量:
1.靜態分配的互斥量不需要銷毀。
2.不要銷毀一個已經加鎖的互斥量。
3.已經銷毀的互斥量,要確保后面的不會有線程再嘗試加鎖。
int pthread_mutex_destroy(pthread_mutex_t *mutex);
互斥量的加鎖與解鎖:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失敗返回錯誤號。
則可改進上邊的售票系統:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<pthread.h>
5
6 int ticket=100;
7 pthread_mutex_t mutex;
8
9 void*thread_run(void*arg)
10 {
11 int a=(int)arg;
12 while(1){
13 pthread_mutex_lock(&mutex);//加鎖
14 if(ticket>0){
15 usleep(10000);
16 printf("%d sells ticket:%d\n",a ,ticket);
17 ticket--;
18 pthread_mutex_unlock(&mutex);//解鎖
19 }else{
20
21 pthread_mutex_unlock(&mutex);//解鎖
22 break;
23 }
24 }
25 }
26 int main()
27 {
28 pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//初始化互斥量
29 pthread_t t1,t2,t3,t4;
30 void*ret1;
31 void*ret2;
32 void*ret3;
33 void*ret4;
34 pthread_create(&t1,NULL,thread_run,(void*)1);
35 pthread_create(&t2,NULL,thread_run,(void*)2);
36 pthread_create(&t3,NULL,thread_run,(void*)3);
37 pthread_create(&t4,NULL,thread_run,(void*)4);
39 pthread_join(t1,&ret1);
40 pthread_join(t2,&ret2);
41 pthread_join(t3,&ret3);
42 pthread_join(t4,&ret4);
43 }
運行結果:
線程同步:
1. 條件變量
- 當一個線程互斥地訪問某個變量時,它可能發現在其他線程改變狀態之前,它什么也做不了。
- 例如一個線程訪問隊列時,發現隊列為空,它只能等待。直到其他線程將一個節點添加到隊列中。
- 所以條件變量相當于一個中介。如一個搶答器,兩人同時按其的過程。
- 多線程條件下通知某些事件已經就緒的方式。
條件變量函數:
初始化:
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);
參數:
cond:要初始化的條件變量
attr:NULL
銷毀:int pthread_cond_destroy(pthread_cond_t *cond)
等待條件滿足:
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
參數:
cond:要在此條件變量上等待
mutex:互斥量,因為在等待時需要將鎖釋放掉。
喚醒條件:
int pthread_cond_signal(pthread_cond_t *cond);
一個簡單的案例:
1 #include<stdio.h>
2 #include<pthread.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<stdlib.h>
6
7 pthread_cond_t cond;
8 pthread_mutex_t mutex;
9
10 void*r1(void*arg)
11 {
12 while(1){
13 pthread_cond_wait(&cond,&mutex);
14 printf("hello\n");
15 }
16 }
17 void *r2(void*arg)
18 {
19 while(1){
20 pthread_cond_signal(&cond);
21 sleep(1);
22 }
23 }
24 int main()
25 {
26 pthread_t t1,t2;
27 pthread_mutex_init(&mutex,NULL);
28 pthread_create(&t1,NULL,r1,NULL);
29 pthread_create(&t2,NULL,r2,NULL);
30 pthread_join(t1,NULL);
31 pthread_join(t2,NULL);
32 pthread_mutex_destroy(&mutex);
33 pthread_cond_destroy(&cond);
34 }
~
運行結果顯示:(每隔1秒打印一個hello world)
2. POSIX信號量(用于實現線程同步)
初始化信號量:
#include<semaphore.h>
int sem_init(sem_t *sem,int pshared,unsigned int value);
參數:
pshared:0表示線程間共享,非0表示進程間共享
value:信號量初始值。
申請信號量不成功時,則申請的線程會被掛起。
銷毀信號量:
#include<semaphore.h>
int sem_destroy(sem_t *sem)
等待信號量(p操作)
功能:會將信號量的值減1
int sem_wait(sem_t *sem);
發布信號量(v操作)
功能:表示資源使用完畢,可以歸還資源了,將信號量值加1.
int sem_post(sem_t *sem)
好了,具體的代碼會在下篇博客生產者、消費者模型中呈現。
智能推薦
【Linux】線程互斥量與條件變量
一.互斥量(mutex) 1.基本概念 在線程之間,因為線程組內所有線程共享進程的地址空間,所以對于每個線程來說,它的絕大多數資源都是與其他線程共享的,所以在多線程程序中,極有可能因為多個線程同時訪問臨界資源,而造成數據的二義性問題。所以這里就引入了同步與互斥機制來保護臨界資源 大部分情況,線程使用的數據都是局部變量,變量的地址空間在線程棧空間內,這種情況,變量歸于單個線程,其他線程語法獲得者種變...
線程的同步控制---信號量、互斥鎖、條件變量
一、線程同步 原因:線程之間擁有許多共享資源,當此資源被多個線程進行訪問時容易造成數據錯誤,程序崩潰,所以需要對線程的臨界資源進行同步控制。 同步:多進程和多線程訪問臨界資源時,需要進行同步控制。多線程或者多進程的執行并不會完全的并行運行,有可能主線程需要等待函數線程的某些條件的發生。 多線程之間臨界資源: 全局數據 堆區數據文件描述符 線程之間的同步控制方式: 3.1信號量 #include&l...
09_線程同步_互斥鎖_讀寫鎖_條件變量_信號量
目錄 1. 概念 1.1、線程同步 1.2、臨界資源 1.3、臨界區 2. 互斥鎖(互斥量) 2.1、互斥鎖類型? 2.2、互斥鎖特點? 2.3、互斥鎖相關函數 3. 死鎖 3.1、死鎖 的幾種場景 3.1.1、忘記釋放鎖,自己將自己鎖住 3.1.2、單線程重復申請鎖 3.1.3、多線程多鎖申請, **搶占鎖資源** 3.2、死鎖的解決 4. 讀寫鎖 1.讀寫鎖類型? 是幾把鎖? 2.讀寫鎖的特點...
linux學習---線程同步(互斥量,信號量,條件量)線程屬性
進程 系統中程序執行和資源分配的基本單位 每個進程有自己的數據段、代碼段和堆棧段 在進行切換時需要有比較復雜的上下文切換 線程 減少處理機的空轉時間,支持多處理器以及減少上下文切換開銷, 比創建進程小很多 進程內獨立的一條運行路線 處理器調度的最小單元,也稱為輕量級進程 可以對進程的內存空間和資源進行訪問,并與同一進程中...
【Linux】深入理解線程(線程同步、互斥量mutex、死鎖、讀寫鎖、條件變量、信號量)
一、同步概念 1、線程同步: 同步即協同步調,按預定的先后次序運行。 線程同步,只一個線程發出某一功能調用時,在沒有得到結果之前,該調用不返回。同時,其他線程為保證數據一致性,不...
猜你喜歡
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...