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 ;
}