執行緒同步:互斥鎖,訊號量
同步概念:
當多個執行緒共享相同的一塊記憶體時(實際上在一個程序的各個執行緒之間,除了棧區的資料之外,其他的資料這幾個縣城之間都是相互共享的),需要確保每個執行緒看到一致的資料檢視。也就是說,這些執行緒在對資料進行操作時,應該是同步的,也就是說當一個執行緒正在操作一個數據時,其他執行緒無法同時對該資料進行操作(讀資料除外,因為讀資料不會改動資料的內容)。這就是所謂的執行緒同步。
實現機制:
- 訊號量。
訊號量大致可以分為兩種,一種取自POSIX的實時擴充套件,作用於執行緒。另外一種被稱為系統V訊號量,作用於程序的同步控制。訊號量是一個特殊的變數,它可以被增加或者減少,但對其的關鍵訪問被保證是原子操作
1.訊號量的建立
這個函式初始化由sem指向的訊號量物件,pshread引數控制訊號量的型別,如果其值為0,就表示這個訊號量只能當前程序區域性使用,否則,這個訊號量就可以在多個程序之間共享。但是現在的Linux系統花不支援這種共享,給pshared傳遞一個非0值將導致函式呼叫失敗!
2.訊號量的加減操作
sem_wait()函式表示對該訊號量進行減操作(p操作),引數為訊號量的id所在的地址。
sem_post()函式表示對該訊號量進行加操作(v操作),引數為訊號量的id所在的地址。
3.訊號量的銷燬
和前面的函式相同,這個函式的引數也是訊號量的id所在的地址。
-
互斥鎖。pthread執行緒庫有一個互斥介面,可以確保同意時間只有一個執行緒訪問資料。互斥量從本質上說是一把鎖,在訪問共享資源前對互斥量進行加鎖,訪問完成後釋放互斥量上的鎖。對互斥量進行加鎖後,其他任何試圖再次對互斥量進行加鎖的執行緒都會阻塞,直到當前執行緒釋放該互斥鎖
1.互斥鎖的實現
互斥變數用pthread_mutex_t資料型別來表示,在使用護持變數之前必須先對其進行初始化。可通過呼叫pthread_mutex_init函式進行初始化,在釋放記憶體前需要呼叫pthread_mutex_destroy函式進行釋放。
第一個引數就是我們申請的護持變數的地址,如果要使用預設的屬性初始化互斥量,只需要把attr引數設定為NULL。而我們大多書情況下也都是這樣做的。
2.給互斥量加鎖,解鎖
對互斥量進行加鎖,需要呼叫pthread_mutex_lock函式,如果互斥量已經上鎖,則呼叫該函式的執行緒將阻塞到互斥量被解鎖。對互斥量進行解鎖,要呼叫pthread_mutex_unlock.
如果執行緒不希望被阻塞,它可以使用pthread_mutex_trylock嘗試對互斥量進行加鎖,如果呼叫該函式時互斥量未被加鎖,那麼該函式將對互斥量進行加鎖,不會阻塞並返回0,否則該函式呼叫失敗,返回一個EBUSY的巨集。
訊號量示例:
使用兩個訊號量實現兩個執行緒的交替列印。
/*************************************************************************
> File Name: main.c
> Created Time: Fri 26 Oct 2018 08:14:50 PM CST
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<pthread.h>
#include<semaphore.h>
sem_t sem1;
sem_t sem2;
static int flag = 0;
void *func(void *ptr)
{
int i = 0;
for(; i < 5; i++)
{
sem_wait(&sem2);
printf("func running\n");
sem_post(&sem1);
}
flag = 1;
printf("func return\n");
sem_post(&sem1);
}
int main()
{
sem_init(&sem1, 0,1);
sem_init(&sem2,0,1);
pthread_t pth;
int err = pthread_create(&pth, NULL,func,NULL);
assert(err == 0 );
int i = 0;
for(; i < 8; i++)
{
if(flag == 0)
sem_wait(&sem1);
printf("main running\n");
if(flag == 0)
sem_post(&sem2);
}
pthread_exit(NULL);
return 0;
}
互斥鎖示例:
同樣實現交替列印;
/*************************************************************************
> File Name: main.c
> Created Time: Fri 26 Oct 2018 08:14:50 PM CST
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<pthread.h>
#include<semaphore.h>
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
static int flag = 0;
void *func(void *ptr)
{
int i = 0;
for(; i < 5; i++)
{
pthread_mutex_lock(&mutex1);
printf("func running\n");
pthread_mutex_unlock(&mutex2);
}
flag = 1;
printf("func return\n");
pthread_mutex_unlock(&mutex2);
}
int main()
{
int err1 = pthread_mutex_init(&mutex1,NULL);
assert(err1 == 0);
int err2 = pthread_mutex_init(&mutex2,NULL);
assert(err2 == 0);
pthread_t pth;
int err = pthread_create(&pth, NULL,func,NULL);
assert(err == 0 );
int i = 0;
for(; i < 8; i++)
{
if(flag == 0)
pthread_mutex_lock(&mutex2);
printf("main running\n");
if(flag == 0)
pthread_mutex_unlock(&mutex1);
}
pthread_exit(NULL);
return 0;
}