信號量和互斥鎖的區別
互斥量用于線程的互斥,信號量用于線程的同步。
這是互斥量和信號量的根本區別,也就是互斥和同步之間的區別。
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源
互斥量值只能為0/1,信號量值可以為非負整數。
也就是說,一個互斥量只能用于一個資源的互斥訪問,它不能實現多個資源的多線程互斥問題。信號量可以實現多個同類資源的多線程互斥和同步。當信號量為單值信號量是,也可以完成一個資源的互斥訪問。
互斥量的加鎖和解鎖必須由同一線程分別對應使用,信號量可以由一個線程釋放,另一個線程得到。
讀者優先
使用互斥鎖來確保同一時間只能一個進程寫文件,實現互斥。使用信號量來實現訪問資源的同步。
首先,寫者的代碼應該是這樣一種形式,才能保證同一時刻只有一個寫者修改數據。
考慮到寫者對讀者的影響是:當任何讀者想讀時,寫者都必須被阻塞;并且,讀者阻塞了寫者并停止阻塞之前,后續的任何寫者都會讀者優先于執行。這就如同有一個讀者隊列,當第一個讀者入隊時,寫者完全被阻塞,直到最后一個讀者離開隊列。
據此,可以用 readerCnt來統計讀者的數量,而用信號量 sem_read來互斥各線程對 readerCnt的訪問。
/*
* 多線程,讀者優先
*/
#include “stdio.h”
#include
#include
#include
#define N_WRITER 30 //寫者數目
#define N_READER 5 //讀者數目
#define W_SLEEP 1 //控制寫頻率
#define R_SLEEP 1 //控制讀頻率
pthread_t wid[N_WRITER],rid[N_READER];
pthread_mutex_t mutex_write;//同一時間只能一個人寫文件,互斥
sem_t sem_read;//同一時間只能有一個人訪問 readerCnt
int data = 0;
int readerCnt = 0;
void write()
{
int rd = rand();
printf(“write %d\n”,rd);
data = rd;
}
void read()
{
printf(“read %d\n”,data);
}
void * writer(void * in)
{
// while(1)
// {
pthread_mutex_lock(&mutex_write);
printf(“寫線程id%d進入數據集\n”,pthread_self());
write();
printf(“寫線程id%d退出數據集\n”,pthread_self());
pthread_mutex_unlock(&mutex_write);
sleep(W_SLEEP);
// }
pthread_exit((void *) 0);
}
void * reader (void * in)
{
// while(1)
// {
sem_wait(&sem_read);
readerCnt++;
if(readerCnt == 1){
pthread_mutex_lock(&mutex_write);
}
sem_post(&sem_read);
printf(“讀線程id%d進入數據集\n”,pthread_self());
read();
printf(“讀線程id%d退出數據集\n”,pthread_self());
sem_wait(&sem_read);
readerCnt--;
if(readerCnt == 0){
pthread_mutex_unlock(&mutex_write);
}
sem_post(&sem_read);
sleep(R_SLEEP);
// }
pthread_exit((void *) 0);
}
int main()
{
printf(“多線程,讀者優先\n”);
pthread_mutex_init(&mutex_write,NULL);
sem_init(&sem_read,0,1);
int i = 0;
for(i = 0; i 《 N_WRITER; i++)
{
pthread_create(&wid[i],NULL,writer,NULL);
}
for(i = 0; i 《 N_READER; i++)
{
pthread_create(&rid[i],NULL,reader,NULL);
}
sleep(1);
return 0;
}
讀者優先
為了更明顯的看到效果,在main函數中創建了20個寫者和5個讀者。注意編譯時要加上-lpthread指定庫。
寫者優先
寫者優先與讀者優先的不同是:如果讀者來,有寫者等待,但有其他讀者正在讀,新讀者等。
使用兩個互斥鎖mutex_write,mutex_read和兩個信號量sem_read,sem_write來確保訪問資源的互斥和同步。
#include “stdio.h”
#include
#include
#include
#define N_WRITER 5 //寫者數目
#define N_READER 20 //讀者數目
#define W_SLEEP 1 //控制寫頻率
#define R_SLEEP 0.5 //控制讀頻率
pthread_t wid[N_WRITER],rid[N_READER];
int data = 0;
int readerCnt = 0, writerCnt = 0;
pthread_mutex_t sem_read;
pthread_mutex_t sem_write;
pthread_mutex_t mutex_write;
pthread_mutex_t mutex_read;
void write()
{
int rd = rand();
printf(“write %d\n”,rd);
data = rd;
}
void read()
{
printf(“read %d\n”,data);
}
void * writer(void * in)
{
// while(1)
// {
sem_wait(&sem_write);
{//臨界區,希望修改 writerCnt,獨占 writerCnt
writerCnt++;
if(writerCnt == 1){
//阻止后續的讀者加入待讀隊列
pthread_mutex_lock(&mutex_read);
}
}
sem_post(&sem_write);
pthread_mutex_lock(&mutex_write);
{//臨界區,限制只有一個寫者修改數據
printf(“寫線程id%d進入數據集\n”,pthread_self());
write();
printf(“寫線程id%d退出數據集\n”,pthread_self());
}
pthread_mutex_unlock(&mutex_write);
sem_wait(&sem_write);
{//臨界區,希望修改 writerCnt,獨占 writerCnt
writerCnt--;
if(writerCnt == 0){
//阻止后續的讀者加入待讀隊列
pthread_mutex_unlock(&mutex_read);
}
}
sem_post(&sem_write);
sleep(W_SLEEP);
// }
pthread_exit((void *) 0);
}
void * reader (void * in)
{
// while(1)
// {
//假如寫者鎖定了mutex_read,那么成千上萬的讀者被鎖在這里
pthread_mutex_lock(&mutex_read);//只被一個讀者占有
{//臨界區
sem_wait(&sem_read);//代碼段 1
{//臨界區
readerCnt++;
if(readerCnt == 1){
pthread_mutex_lock(&mutex_write);
}
}
sem_post(&sem_read);
}
pthread_mutex_unlock(&mutex_read);//釋放時,寫者將優先獲得mutex_read
printf(“讀線程id%d進入數據集\n”,pthread_self());
read();
printf(“讀線程id%d退出數據集\n”,pthread_self());
sem_wait(&sem_read);//代碼段2
{//臨界區
readerCnt--;
if(readerCnt == 0){
pthread_mutex_unlock(&mutex_write);//在最后一個并發讀者讀完這里開始禁止寫者執行寫操作
}
}
sem_post(&sem_read);
sleep(R_SLEEP);
// }
pthread_exit((void *) 0);
}
int main()
{
printf(“多線程,寫者優先\n”);
pthread_mutex_init(&mutex_write,NULL);
pthread_mutex_init(&mutex_read,NULL);
sem_init(&sem_write,0,1);
sem_init(&sem_read,0,1);
int i = 0;
for(i = 0; i 《 N_READER; i++)
{
pthread_create(&rid[i],NULL,reader,NULL);
}
for(i = 0; i 《 N_WRITER; i++)
{
pthread_create(&wid[i],NULL,writer,NULL);
}
sleep(1);
return 0;
}
寫者優先
評論
查看更多