读者-写着问题

定义:

读者-写者问题是为了解决同步和并发机制的,有一个多个进程共享的数据区,这个数据区可以是一个文件或者一块内存空间,甚至可以是一组寄存器。有一些进程(reader)只读取这个数据区中的数据,一些进程(writer)只网数据区写数据;此外还必须满足以下条件:

1. 任意多的读进程可以同时读这个文件。
2. 一次只有一个写进程可以写文件。
3. 如果一个写进程正在写文件,禁止任何读进程读文件。

也就是说,读进程是不需要排斥其他读进程的,而写进程是需要排斥其他所有进程的,包括读进程和写进程。

先看一下P V操作。

1. 信号量
PV操作与信号量的处理有关,信号量是表示资源的实体,是一个与队列有关的整型变量,其值只能由P、V操作来改变。操作系统利用信号量对进程和资源进行控制和管理。

2. PV操作
信号量(Saphore)由一个值和一个指针组成,指针指向等待该信号量的进程。信号量的值表示相应资源的使用情况。S表示信号量的使用情况;当执行一个P操作时,表示请求分配一个资源,因此S的值减1,当S的值小于0时,表示系统没有可用资源,进程处于阻塞状态。当执行一个V操作时,表示分配 一个资源,因此S的值加一。

procedure P(var s:samephore);
{
    s.value=s.value-1;
    if (s.value<0) 
    asleep(s.queue);
}
procedure V(var s:samephore);
{
    s.value=s.value+1;
    if (s.value<=0) 
    wakeup(s.queue);
}

asleep(s.queue):执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态

wakeup(s.queue):将s.queue头进程唤醒插入就绪队列

s的初值为1时,可以用来实现进程的互斥,执行流程必须是P操作,V操作,P操作,V操作…

3. 读者优先问题
思路分析: 两个进程,即读者和写者。写者是比较简单的,它和任何进程互斥,用互斥信号量的P操作、V操作即可解决。读者的问题比较复杂,它必须实现与写者互斥的同时还要实现与其他读者的同步,因此,仅仅简单的一对P操作、V操作是无法解决的。那么,在这里用到了一个计数器count,用它来判断当前是否有读者读文件。当有读者的时候写者是无法写文件的,此时读者会一直占用文件,当没有读者的时候写者才可以写文件。同时这里不同读者对计数器的访问也应该是互斥的。

首先设置信号量count为计数器,用来记录当前读者数量,初值为0; 设置mutex为互斥信号量,用于保护更新count变量时的互斥;设置互斥信号量rw用于保证读者和写者的互斥访问。

int count=0;   //用于记录当前读者的数量
semaphore mutex=1;  //用于保护更新count变量时的互斥
semaphore rw=1;  //用于保证读者和写着互斥

void reader(){
	while(true){
		P(mutex);    //互斥访问count变量
		if(count==0)  //当第一个读进程共享文件时,阻止写文件
			P(rw);   
		count++;  //读者计数增加
		V(mutex);  //释放互斥量count
		reading;   //读取
		P(mutex);  //互斥访问count
		count--;  
		if(count==0)
			V(rw);  //当最后一个进程读完共享文件 允许写文件
		V(mutex);
	}
}

void wirter(){
	while(true){
		P(rw);  //互斥地访问共享资源
		writing;  //写入
		V(rw);  //释放
	}
}

在这个算法中,读进程是优先的,也就是说在读进程的时候不允许写进程,但允许多个进程进行读,所以写操作将被延迟,并且只要有一个读进程活跃,随后而来的读进程都将被允许访问文件。这样的方式下,会导致写进程可能长时间等待,且存在写进程"饿死"的情况。

改进方法:当有读进程正在读取共享文件时,有写进程请求访问,这时应禁止后续读进程给的请求,等待到已在共享文件执行完毕则立即让写进程执行,只有在无写进程的情况下才被允许读进程再次运行。为此,增加一个信号量,就可以得到写进程优先的解决程序。

4. 写进程优先

int count=0;   //记录当前读者数量
semaphore mutex = 1;  //保护更新count变量
semaphore re = 1;  //用于保证读者和写者互斥地访问文件
semaphore w = 1;  //用于实现写优先

void reader(){
	while(true){
		P(w);  //在无写进程时请求进入
		P(mutex);  //互斥访问count
		if(count==0)  //当第一个读进程共享文件时
			P(rw);  //阻止写进程
		count++V(mutex);  //释放互斥量count;
		V(w);  //恢复对共享文件的访问
		reading;  //读取
		P(mutex);  //互斥访问count
		count--;
		if(count==0) //当最后一个读进程读完共享文件时
			V(rw);   //允许写进程
		V(mutex);  //释放互斥量count
	}
}

void writer(){
	while(true){
		P(w);  //在无写进程请求进入
		P(rw);
		writing;
		V(rw);
		V(w);   //恢复对共享文件的访问
	}
}

参考:https://blog.csdn.net/u014253011/article/details/82744241

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值