二十、经典同步问题-读者写者问题

本文详细介绍了读者-写者问题,这是一个经典的多线程同步问题。通过信号量和管程两种机制实现,确保在并发环境中,多个读者可以同时读取但只有一个写者能修改数据,并且读者优先。文章提供了具体的信号量操作逻辑和管程实现的伪代码,展示了如何使用条件变量来协调读者和写者的访问顺序。
摘要由CSDN通过智能技术生成

1、读者-写者问题描述

\qquad 动机: 共享数据的访问,假设有两种类型的使用者:一种为读者,不需要修改数据;另一种为写者,其会读取和修改数据。问题的约束包括: 允许在同一时间有多个读者,但在任何时候都只有一个写者;当没有写者时,读者才能访问数据;当没有读者和写者时,写者才能访问数据;在任何时候只能有一个线程可以操作共享变量;读者优先,若在读者前面有写者在排队等待,读者可以越过写者优先进行排队。
\qquad 设计算法需要用到的共享数据: 包括数据集,信号量(CountMutex)初始化为1,信号量(WriteMutex)初始化为1,整数Rcount初始化为0(记录当前读者的个数)。

2、基于信号量实现

\qquad 基于读者优先和信号量的操作逻辑如下所示:

//基于信号量的writer操作逻辑
sem_wait(WriteMutex);//P操作-1,保证同一时间只有一个进程可以进行写操作
	write;
sem_post(WriteMutex);//V操作+1
//基于信号量的Reader操作逻辑
sem_wait(CountMutex);//对Rcount进行保护,进行线程互斥
	if(Rcount == 0)
		sem_wait(WriteMutex);//P操作-1,保证同一时间只有一个进程可以进行写操作
	++Rcount;
sem_post(CountMutex);

read;

--Rcount;
sem_wait(CountMutex);//对Rcount进行保护,进行线程互斥
	if(Rcount == 0)
		sem_post(WriteMutex);//V操作+1,当最后一个读者读完之后,释放线程锁,让写者进来
sem_post(CountMutex);

3、基于管程实现

\qquad 基于写者优先和管程的操作逻辑如下所示:

//基于管程的reader操作逻辑伪代码如下所示
Database::Read()
{
	Wait until no writers;//这里读者需要等待正在临界区进行操作的写者和处于等待状态的写者
	read database;
	check out - wake up waiting writers;//唤醒处于等待状态的写者
}
//基于管程的writer操作逻辑
Database::Write()
{
	Wait until no readers/writers;//这里写者需要等待正在进行操作的读者或者写者
	write database;
	check out - wake up waiting readers/writers;//唤醒处于等待状态的读者
}
//管程中的条件变量包括以下
AR=0;//正在进行读操作的reader的个数
AW=0;//正在进行写操作的writer的个数
WR=0;//等待队列中处于等待状态的reader的个数
WW=0;//等待队列中处于等待状态的writer的个数
Condition okToRead;//条件变量,表示当前是否可以进行读操作了
Condition okToWrite;//条件变量,表示当前是否可以进行写操作了
Lock lock;
Public Database::Read()
{
	//管程实现reader
	StartRead();//Wait until no writers
	read databasel
	DoneRead();//check out - wake up waiting writers
}
Private Database::StartRead()
{
	lock.Acquire();//确保只有一个进程进入到管程之中
	while(AW+WW>0) //若有正在等待或者正在进行写操作的writer
	{
		++WR;
		okToRead.wait(&lock);
		--WR;
	}
	++AR;
	lock.Release();
}

Private Database::DoneRead()
{
	lock.Acquire();//确保只有一个进程进入到管程之中
	--AR;
	if(AR == 0 && WW > 0)//若当前没有正在进行读操作的reader了同时有正在等待的writer
	{
		okToWrite.signal();//唤醒一个正在等待的writer
	}
	lock.Release();
}
Public Database::Write()
{
	//管程实现Writer
	StartWrite();//Wait until no readers/writers
	read databasel
	DoneWrite();//check out - wake up waiting readers/writers
}
Private Database::StartWrite()
{
	lock.Acquire();//确保只有一个进程进入到管程之中
	while(AR+AW>0) //若有正在进行读操作的reader或者正在进行写操作的writer
	{
		++WW;
		okToWrite.wait(&lock);
		--WW;
	}
	++AW;
	lock.Release();
}

Private Database::DoneWrite()
{
	lock.Acquire();//确保只有一个进程进入到管程之中
	--AW;
	if(WW > 0)//若当前有正在等待的writer
		okToWrite.signal();//唤醒一个正在等待的writer
	else if(WR > 0)//若当前有正在等待的reader
		okToRead.broadcast();//唤醒等待在条件变量上的所有的reader
	
	lock.Release();
}

THE END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dragon Fly

多谢老板赏钱[抱拳抱拳抱拳]

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值