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