1. 程式人生 > >linux下多執行緒同步機制之訊號量、互斥量、讀寫鎖、條件變數

linux下多執行緒同步機制之訊號量、互斥量、讀寫鎖、條件變數

之前有寫過類似的部落格,這東西不用老忘,現在又有更清晰的理解了。

一、訊號量

編譯時候加入-lrt

訊號量最基本的兩個操作就是PV操作:P()操作實現訊號量減少,V()操作實現訊號量的增加

訊號量的值取決於訊號量的型別,訊號量的型別有多種:

(1)二進位制訊號量:0與1.

    當值=1時,訊號量可用,當值=0時候,訊號量不可用,這裡就可以利用P()V()操作來實現,如果=0時候,執行緒阻塞在P()操作

(2)計數訊號量

    某個非負整數,初始值表示可用的資源數,例如我們實現兩個執行緒,一個執行緒專門執行V()操作  另一個專門執行P()操作 那麼生產者,消費著的行為就是如此!!

//============================================================================
// Name        : ThreadTest.cpp
// Author      : YLF
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>

using namespace std;

char *semName = "/SEM";
sem_t *sem;


void* Producer(void* para){
	int n = 10;
	while(n>0){
		sem_post(sem);
		cout<<"produce"<<endl;
		n--;
	}
}

void* Consumer(void* para){
	int n = 10;
	while(n>0){
		sem_wait(sem);
		cout<<"consumer"<<endl;
		n--;
	}
}

int main() {

	sem = sem_open(semName, O_CREAT, O_RDWR, 0);

	pthread_t thread1,thread2;
	pthread_create(&thread1,NULL,Producer,NULL);
	pthread_create(&thread2,NULL,Consumer,NULL);

	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);

	sem_close(sem);
	sem_unlink(semName);
	return 0;
}

produce
produceconsumer
consumer

produce
produce
produce
produce
produce
produce
produce
produce
consumer
consumer
consumer
consumer
consumer
consumer
consumer
consumer


我們發現,上面這種方式不是一個很好的原子操作!

當然,也可以利用0-1這種實現原子操作

就是將訊號量初始化為1,然後Producer()和Consuer()這兩個執行緒都執行

sem_wait()

受限制的資源操作

sem_post()

這種方式就可以阻塞另一個想要佔用同一個資源的執行緒

訊號量的好處就是可以實現程序間的通訊!

二、POSIX還提供了另一種實現機制,利用MUTEX  pthread_mutex_t  

編譯時候加入-lpthread  

#include <pthread.h>

#include <fcntl.h>

這個互斥量的使用方式

初始化:

mutex = PTHREAD_MUTEX_INITIALIZER;//靜態初始化

pthread_mutex_init(&mutex, NULL);//動態初始化

請求佔有:

pthread_mutex_lock(&mutex)

釋放佔有:

pthread_mutex_unlock(&mutex);

嘗試佔有:

pthread_mutex_trylock(&mutex);

銷燬:

pthread_mutex_destroy(&mutex);

三、讀寫鎖

互斥量訊號量都是臨界區實現,只有使用共享資料的執行緒或程序才能進入。可是,當我們有多個執行緒只是希望讀取資料的時候,他們之間會進行阻塞,而我們並不希望這樣,只希望寫執行緒才會對別的產生阻塞

如果多個執行緒對共享記憶體進行寫訪問,則不允許其他執行緒進入臨界區,如果應用程式有多個執行緒希望讀,則可以進入臨界區。

POSIX定義了型別為pthread_rwlock_t 的讀寫鎖

初始化:

pthread_rwlock_init(pthread_rwlock_t*, attr)

請求佔有:

pthread_rwlock_rdlock(*lock)

pthread_rwlock_wrlock(*lock);

pthread_rwlock_timedrdlock()...

釋放佔有:

pthread_rwlock_unlock(*lock)

嘗試和銷燬

四、條件變數

互斥量通過 控制 對共享資料的訪問來同步任務。條件變數可以根據資料的值來同步任務。條件變數是當一個事件發生時傳送訊號的訊號量。一旦事情發生,可能會有多個程序或執行緒在等待訊號。條件變數通常用於對操作的順序進行同步。

條件變數型別pthread_cond_t

初始化:

pthread_cond_init(pthread_cond_t*,*attr)

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

傳送訊號:

pthread_cond_signal(*cond)

pthread_cond_broadcast(*cond)

銷燬

pthread_cond_destroy(*cond);

阻塞:

pthread_cond_wait(*cond,*mutex)

pthread_mutex_t mutex, eventMutex;
pthread_cond_t cond;

void* ThreadA(void *para){
	int num = 10;
	while(num>0){
		pthread_mutex_lock(&mutex);
		num--;
		cout<<"ThreadA:"<<num<<endl;
		if(num  == 6)
			pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mutex);
	}
}

void* ThreadB(void* para){
	int num = 10;

	pthread_mutex_lock(&eventMutex);
	pthread_cond_wait(&cond, &eventMutex);
	pthread_mutex_unlock(&eventMutex);
	while(num>0){
		pthread_mutex_lock(&mutex);
		num--;
		cout<<"ThreadB:"<<num<<endl;
		pthread_mutex_unlock(&mutex);
	}
}

int main() {

	pthread_mutex_init(&mutex, NULL);
	pthread_mutex_init(&eventMutex, NULL);

	pthread_t thread1,thread2;
	pthread_create(&thread2,NULL,ThreadB,NULL);
	pthread_create(&thread1,NULL,ThreadA,NULL);

	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);
        return 0 ;
}