Linux系統編程之線程控制及線程間同步互斥機制:POSIX信號量和互斥鎖
聲明:侵刪
文章目錄
1. 線程和進程的區別
進程 :每個進程有自己獨立的地址空間
Linux為每個進程創建task_struct (任務結構體,存放進程屬性)
每個進程都參與內核調度,不影響其他進程
線程:進程在切換時系統開銷大
很多操作系統引入了輕量級進程LWP(線程)
同一進程中的線程共享相同地址空間
Linux不區分進程、線程(Linux都認為成一個任務)
一個進程中的多個線程共享一下資源
線程ID
PC和相關寄存器
堆棧
errno
優先級
執行狀態和屬性
2.prhread線程庫相關API
編譯時候要注意鏈接pthread線程庫
線程創建函數:pthread_creat
線程回收函數: pthread_join
線程退出函數:pthread_exit
3.線程間的同步和互斥
線程共享進程的空間地址和資源,對這些資源進行操作是必須注意線程間的同步和互斥。本文主要介紹POSIX的兩種互斥機制: 信號量和互斥鎖。
互斥鎖適用于同時可用資源唯一的情況,信號量適合于同時可用資源為多個的情況。
4.互斥鎖
互斥鎖是一種以簡單的加鎖方式對共享資源的原子操作。互斥鎖有兩種狀態:上鎖和解鎖。在同一時刻只有一個線程可以掌握互斥鎖,擁有上鎖狀態的線程可以對共享資源進行操作,其余線程想要搶鎖就會掛起直到擁有鎖的進程釋放鎖。
互斥鎖可以分為快速互斥鎖、遞歸互斥鎖、檢錯互斥鎖。
快速鎖:調用線程必須堵塞到擁有鎖的進程釋放鎖為止
遞歸鎖:遞歸鎖能夠成功的返回,并能增加調用線程在互斥上加鎖的次數
檢錯鎖:相當于非堵塞版的快速鎖,搶不到鎖不會堵塞會返回一個錯誤信息。
默認是快速互斥鎖。
使用互斥鎖之前必須初始化鎖的類型。
互斥鎖相關API
互斥鎖初始化函數 pthread_mutex_init
互斥鎖控制函數:上鎖、解鎖、檢查鎖、刪除鎖、
5.互斥鎖例程
/*mutex.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define THREAD_NUM 3 /*線程數*/
#define TASKK_NUM 3 /*每個線程執行的小任務數*/
#define DELAY_TIME 10 /*每個小任務最大時間間隔*/
pthread_mutex_t mutex; /*定義互斥鎖*/
/*線程函數*/
void * func_thread(void *arg)
{
int thread_num = (int) arg;
int delay_time = 0;
int count = 0;
if (pthread_mutex_lock(&mutex) == -1)/*搶鎖*/
{
perror("pthread_mutex_lock");
pthread_exit(NULL);
}
printf("The thread [%d] is beginning\n",thread_num);
for(count = 0; count<TASKK_NUM;count++)
{
delay_time =(int)(rand()%DELAY_TIME)+1; /*產生隨機數1-DLY_TIME*/
sleep(delay_time);
printf("\tthread[%d],job[%d],sleep[%d]s\n",thread_num,count,delay_time);
}
printf("pthread[%d] end\n",thread_num);
pthread_mutex_unlock(&mutex);/*解鎖*/
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THREAD_NUM];
int thread_num =0 ;
srand((time(NULL))); /*初始化隨機數種子*/
pthread_mutex_init(&mutex,NULL);/*初始化互斥鎖為快速互斥鎖*/
/*創建線程*/
for( thread_num=0;thread_num < THREAD_NUM;thread_num ++)
{
if (pthread_create(&tid[thread_num],NULL,func_thread,(void *) thread_num) != 0)
{
printf("Create pthread[%d] failed\n",thread_num);
exit(-1);
}
}
printf("Creat all thread sucessed,please waitting ...\n" );
/*回收進程*/
for(thread_num = 0;thread_num <THREAD_NUM;thread_num++)
{
pthread_join(tid[thread_num],NULL);
printf("thread[%d] joined\n",thread_num);
}
pthread_mutex_destroy(&mutex); /*刪除鎖*/
exit(1);
}
結果對比
6.POISX信號量 System V 信號量參考此文
信號量實質是一個非負整數的計數器,是操作系統中的PV原語,常用于線程間的同步與互斥。
一次 P 操作使信號量sem 減 1, 而一次 V 操作使 sem 加 1。 進程( 線程) 根據信號量的值來判斷是否對公共資源具有訪問權限。當 sem 的值大于等于 0 時,該進程(或線程)具有公共資源的訪問權限;相反,當 sem 的值小于 0 時,該進程(線程)就將阻塞直到 sem 的值大于等于 0 為止。
信號量常用語進程(線程)之間的同步或者互斥
互斥 當信號量作互斥作用時,往往設置一個信號量來決定資源歸屬
同步信號量做同步機制時,往往設置多個信號量,通過初始化值和PV操作來決定他們的運行順序。
POSIX信號量相關API
信號量創建初始化函數 sem_init
信號量操作函數 PV操作、刪除、獲取信號量的值
**
7.POSIX信號量例程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#define THREAD_NUM 3 /*線程數*/
#define TASKK_NUM 3 /*每個線程執行的小任務數*/
#define DELAY_TIME 10 /*每個小任務最大時間間隔*/
sem_t sem[THREAD_NUM];
/*線程函數*/
void * func_thread(void *arg)
{
int thread_num = (int) arg;
int delay_time = 0;
int count = 0;
/*每個線程首先進行P操作 ,判斷有無資源*/
sem_wait(&sem[thread_num]);
printf("The thread [%d] is beginning\n",thread_num);
for(count = 0; count<TASKK_NUM;count++)
{
delay_time =(int)(rand()%DELAY_TIME)+1; /*產生隨機數1-DLY_TIME*/
sleep(delay_time);
printf("\tthread[%d],job[%d],sleep[%d]s\n",thread_num,count,delay_time);
}
printf("pthread[%d] end\n",thread_num);
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THREAD_NUM];
int thread_num =0 ;
srand((time(NULL))); /*初始化隨機數種子*/
/*創建線程*/
for( thread_num=0;thread_num < THREAD_NUM;thread_num ++)
{
sem_init(&sem[thread_num],0,0);/*將所有信號量初始化為0*/
if (pthread_create(&tid[thread_num],NULL,func_thread,(void *) thread_num) != 0)
{
printf("Create pthread[%d] failed\n",thread_num);
exit(-1);
}
}
/*將最后創建的一個進程進行V操作, sem[THREAD_NUM-1]變為1,最后創建的進程先運行*/
sem_post(&sem[THREAD_NUM-1]);
printf("Creat all thread sucessed,please waitting ...\n" );
/*回收進程*/
for(thread_num = THREAD_NUM -1;thread_num >= 0;thread_num --)
{
pthread_join(tid[thread_num],NULL);
printf("thread[%d] joined\n",thread_num);
/*每回收一個線程就將下一個要運行線程解開,對上一個信號量V操作*/
sem_post(&sem[(thread_num+THREAD_NUM-1)%THREAD_NUM]);
}
/*刪除信號量*/
for(thread_num = 0;thread_num <THREAD_NUM-1;thread_num++)
{
sem_destroy(&sem[thread_num]);
}
exit(1);
}
結果
智能推薦
線程的同步控制---信號量、互斥鎖、條件變量
一、線程同步 原因:線程之間擁有許多共享資源,當此資源被多個線程進行訪問時容易造成數據錯誤,程序崩潰,所以需要對線程的臨界資源進行同步控制。 同步:多進程和多線程訪問臨界資源時,需要進行同步控制。多線程或者多進程的執行并不會完全的并行運行,有可能主線程需要等待函數線程的某些條件的發生。 多線程之間臨界資源: 全局數據 堆區數據文件描述符 線程之間的同步控制方式: 3.1信號量 #include&l...
【Linux】深入理解線程(線程同步、互斥量mutex、死鎖、讀寫鎖、條件變量、信號量)
一、同步概念 1、線程同步: 同步即協同步調,按預定的先后次序運行。 線程同步,只一個線程發出某一功能調用時,在沒有得到結果之前,該調用不返回。同時,其他線程為保證數據一致性,不...
使用信號量控制線程互斥和同步。
首先要知道PV原語的概念。以下是百度百科對PV原語的介紹: PV原語通過操作信號量來處理進程間的同步與互斥的問題。其核心就是一段不可分割不可中斷的程序。 信號量的概念1965年由著名的荷蘭計算機科學家Dijkstra提出,其基本思路是用一種新的變量類型(semaphore)來記錄當前可用資源的數量。有兩種實現方式:1)semaphore的取值必須大于或等于0。0表示當前已沒有空閑資源,而正數表示當...
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壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...