Linux多线程的同步-----信号量和互斥锁
前面兩篇給基本概念講過了,大家有興趣的可以去看一下:
Linux多線程_神廚小福貴!的博客-CSDN博客進程和線程的區別有哪些呢?進程是資源分配的最小單位,線程是CPU調度的最小單位進程有自己的獨立地址空間,線程共享進程中的地址空間進程的創建消耗資源大,線程的創建相對較小進程的切換開銷大,線程的切換開銷相對較小進程:程序執行的過程叫進程。線程:進程內部的一條執行序列或執行路徑,一個進程可以包含多條線程(多線程)!每個進程最少有一個線程,例如下面代碼:#include <stdio.h>int main(){ return 0;} ...https://blog.csdn.net/qq_45829112/article/details/121458560Linux多線程的進階理解_神廚小福貴!的博客-CSDN博客首先來看在Linux中如何實現多線程的,下面是《Linux內核設計與實現第三版》中掃描頁的截圖:這段話我冒昧的解析一下,如有不當,歡迎指出,大家共同進步!在Linux中線程和進程沒有任何區別(站在內核角度來看),每個線程屬于自己的task_struct,task_struct相當于在進程中的PCB(進程描述符),每創建一個新的進程就有一個新的進程描述符,在內核中線程看起來就是普通的進程,但是這個進程和它的主線程(在內核看來就是主進程)共享一塊內存地址,同一個進程描述符!下面來看一段代碼.https://blog.csdn.net/qq_45829112/article/details/121522914
下面來說一下Linux多線程中使用信號量和互斥鎖對多線程進行同步!
先來看一下下面的一段代碼來了解為什么需要對進程進行同步:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h> //多線程的創建  等待  退出所需的頭文件int g_index = 1;void* fun(void* arg)
{for(int i = 0 ; i < 1000 ; i++){printf(" g_index = %d \n",g_index++);}
}int main()
{pthread_t id[5];for(int i = 0 ; i < 5 ; i++){pthread_create(&id[i],NULL,fun,NULL);}for(int i = 0 ; i < 5  ; i++){pthread_join(id[i],NULL);}exit(0);} 
如上代碼所示,該代碼的初衷是想由主線程創建五個子線程來共同對全局變量g_index進行++的操作,理想中打印出來的結果應該是1 2 3? ......? 5000
那么具體結果是如何呢,下面我們來看一下代碼運行的結果:
這是第一次運行::
?這是第二次運行:
?大家可以看看,僅僅是兩次的運行,結果就大不相同,這只是兩次的結果,如果多運行幾次,那么結果可能千變萬化。
我們先來說一下出現這種情況的原因是什么,請看下圖:
?那么如何解決這種情況呢,信號量和互斥鎖
下面來看信號量:
先來看包含他們的頭文件:#include <semaphore.h>?
信號量的初始化:int sem_init(sem_t *sem, int pshared, unsigned int value);?
?第一個參數是信號量的地址;
第二個參數是釋放需要兩線程之間共享,這里我們用不到,給個0就好
第三個參數是信號量的初始值
信號量的p(對信號進行-1的操作)操作:int sem_wait(sem_t *sem);?
信號量的v(對信號量進+1操作)操作:int sem_post(sem_t *sem);?
參數就是信號量的地址
信號量的銷毀:int sem_destroy(sem_t *sem);?
那么對于這道題來說,想要讓五個子線程打印5000個有序的數來說,需要定義多少個信號量呢?大家好好想想,沒思路的話,可以去看看這篇博客:Linux編程題:信號量同步三進程依次打印若干次ABC_神廚小福貴!的博客-CSDN博客
大家是不是以為定義5個信號量,來追著下一個信號量的尾巴,對它進行操作,然后打印嗎?
錯了(也不是完全錯了),上面那種五個信號量適用于進程間的,而在線程中,他們是并發執行的,你要是搞5個信號量的,就是規定了每個線程的打印順序,完全沒必要,我們現在完全不關心誰先打印數字(誰先打印都無所謂的),我們關心的只是多個線程中同時只有一個能進行打印,所以一個信號量足夠了,下面來看代碼:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h> 
#include<semaphore.h>  //信號量操作所需的頭文件sem_t semid;    //定義信號量
int g_index = 1;void* fun(void* arg)
{for(int i = 0 ; i < 1000 ; i++){sem_wait(&semid);   //在g_index++之前進行減一操作,使得其他的線程堵塞printf(" g_index = %d \n",g_index++);sem_post(&semid);   //在g_index++之后進行加一操作,使得其他的線程得以正常運行}
}int main()
{sem_init(&sem,0,1);  //將信號量初始值給1pthread_t id[5];for(int i = 0 ; i < 5 ; i++){pthread_create(&id[i],NULL,fun,NULL);}for(int i = 0 ; i < 5  ; i++){pthread_join(id[i],NULL);}sem_destroy(&semid); //信號量的銷毀函數exit(0);} 
這樣的話,我們來看一下運行結果!
?這樣的話,就讓多線程并發執行進行同步!
下面再來看看互斥鎖:
頭文件就是線程創建函數的頭文件:#include <pthread.h>?
線程同步指的是當一個線程在對某個臨界資源進行操作時,其他線程都不可以對這個資源進行操作,直到該線程完成操作, 其他線程才能操作,也就是協同步調,讓線程按預定的先后次序進行運行。
互斥鎖可以理解為就是在商場試衣間里面,你進去之后給試衣間上鎖,然后其他人就必須等你解鎖之后才可以正常使用這個試衣間,你在使用的時候,其他人只能阻塞(等你使用完)!
互斥鎖的初始化:
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);?
第一個參數是互斥鎖的餓地址
第二個參數是互斥鎖的屬性,一般置為NULL
互斥鎖的上鎖:int pthread_mutex_lock(pthread_mutex_t *mutex);?
互斥鎖的解鎖:int pthread_mutex_unlock(pthread_mutex_t *mutex);?
互斥鎖的銷毀:int pthread_mutex_destroy(pthread_mutex_t *mutex);?
參數都是互斥鎖的地址
下面來看代碼:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h> int g_index = 1;
pthread_mutex_t mutex;   //互斥鎖的定義void* fun(void* arg)
{for(int i = 0 ; i < 1000 ; i++){pthread_mutex_lock(&mutex);    //互斥鎖的上鎖?printf(" g_index = %d \n",g_index++);pthread_mutex_unlock(&mutex);   //互斥鎖的解鎖}
}int main()
{pthread_mutex_init(&mutex,NULL);   //互斥鎖的初始化pthread_t id[5];for(int i = 0 ; i < 5 ; i++){pthread_create(&id[i],NULL,fun,NULL);}for(int i = 0 ; i < 5  ; i++){pthread_join(id[i],NULL);}pthread_mutex_destroy(&mutex);exit(0);} 
然后代碼運行結果和上述的信號量一毛一樣:
信號量和互斥鎖的代碼不難,難的是理解這種思想,因為這是線程,所以在定義信號量的時候,定義一個就夠了,因為誰打印出那個數字,我不在乎,五個子線程誰搶到了誰就打印,但是每次只能有一個子線程在打印,互斥鎖也是如此,每次只能一個線程去打印,理解了思想,這就可以了!
“累的時候,可以休息,但是弓出沒有回頭路,堅持走下去!”
總結
以上是生活随笔為你收集整理的Linux多线程的同步-----信号量和互斥锁的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 求一个qq网名女一个字!
 - 下一篇: “况当故园夜”下一句是什么