读者—写者问题

一、读者—写者问题

对于读者写者,我们在操作系统中进程线程一课就已学习,再结合网上的资料我大致理解为如下几点:

  1. 读者和写者互斥,这里的互斥是指读者和写者不能同时访问共享资源,比如读者进行读文件的操作我们叫做读进程,写者进行写文件的操作我们叫做写进程,这两个进程不能同时进行,即读进程进行时写进程禁止,写进程进行时读进程禁止
  2. 多线程的读者写者问题可以允许有多个写进程和读进程。可以允许多个读进程同时读一个资源,但是不允许多个写进程同时访问一个资源

二、算法分类

1.写者优先算法

写者优先算法就是在满足读者写者互斥的情况下,谁先执行衍生出来的算法,其要点如下:

(1)如果读者来:

如果没有读者、写者在访问资源,新读者可以读;

如果没有写者等待,但有其他读者正在读,新读者可以读;

如果有写者等待,但有其他读者正在读,新读者等待;

如果有写者写,新读者等待

(2)如果写者来:

如果没有读者在读,新写者可以写;

如果有读者在读,新写者等待;

如果有其他写者或等待,新写者等待

2.读者优先算法

(1)有新读者进入

如果没有读者、写者在访问资源,新读者可以读;

如果没有写者正在写,新读者可以读;

如果有写者写,新读者等待。

(2)有新写者进入

如果没有读者在读,新写者可以写;

如果有读者在读,新写者等待;

如果有其他写者在写或在等待,新写者等待

三、实验代码

1.写者优先算法代码

所谓写者优先,即:当有读者进程正在执行,写者进程发出申请,这时应该拒绝其他读者进程的请求,等待当前读者进程结束后立即执行写者进程,只有在无写者进程执行的情况下才能够允许读者进程再次运行。为此,增加一个信号量并且在上面的程序中 writer()和reader()函数中各增加一对PV操作,就可以得到写进程优先的解决程序。

在读者优先的基础上

  • 增加信号量r,初值是1,用于禁止所有的读进程。
  • 增加一个记数器,即整型变量writecount,记录写者数,初值是0(原count改为readcount)。 writecount为多个写者共享的变量,是临界资源。用互斥信号量wmutex控制, wmutex初值是1(原wmutex改为mutex1)。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
 
#define N 5
 
int readcount=0,writecount=0,a=5,b=2;
int r[N]={0,1,2,3,4};
int w[N]={0,1};
sem_t wmutex,rmutex,mutex1,num;
 
 
void delay()
{
	int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒           
	usleep(time * 100000);
}
 
void Reader(void *arg)
{
	int i=*(int *)arg;
	while(a>0)
	{
    		a--;
    		delay();//延迟 
    		
		//进入共享文件前的准备 
    		sem_wait(&num);//在无写者进程时进入 
        	sem_wait(&rmutex);//与其他读者进程互斥的访问readcount 
        	if(readcount==0)
        		sem_wait(&mutex1);//与写者进程互斥的访问共享文件 
        	readcount++;
        	sem_post(&rmutex);
        	sem_post(&num); 
	
		//reader
        	printf("Reader%d is reading!\n",i);
        	printf("Reader%d reads end!\n",i);
        	
        	//退出共享文件后的处理 
        	sem_wait(&rmutex);
        	readcount--;
        	if(readcount==0)
        		sem_post(&mutex1);
        	sem_post(&rmutex);
    	}	
}
 
void Writer(void *arg)
{
	int i=*(int *)arg;
	while(b>0)
    	{
    		b--;
    		delay();
    		
    		//进入共享文件前的准备 
    		sem_wait(&wmutex);//保证多个写者进程能够互斥使用writecount 
    		writecount++;
    		if(writecount==1)
    			sem_wait(&num);//用于禁止读者进程 
    		sem_post(&wmutex);
    		
    		//writer
        	sem_wait(&mutex1);//与其他所有进程互斥的访问共享文件 	
    		printf("writer%d is writing!\n",i); 
        	printf("writer%d writes end!\n",i);
    		sem_post(&mutex1);
        	
        	//退出共享文件后的处理 
        	sem_wait(&wmutex);
    		writecount--;
    		if(writecount==0)
    			sem_post(&num);
    		sem_post(&wmutex);
    	}
}
 
int main()
{
	int i;
	pthread_t writer[N],reader[N];
	srand((unsigned int)time(NULL));
	
	sem_init(&wmutex,0,1);//互斥锁初始化 
	sem_init(&rmutex,0,1);
	sem_init(&mutex1,0,1);	
	sem_init(&num,0,1);
	
	for(i=0;i<5;i++)//创建线程 
	{
		pthread_create(&reader[i],NULL,(void *)Reader,&r[i]);
	} 
	
	for(i=0;i<2;i++)//创建线程 
	{
		pthread_create(&writer[i],NULL,(void *)Writer,&w[i]);
	}
	
	for(i=0;i<2;i++)//等待线程 
	{
		pthread_join(writer[i],NULL);
	}
	
	for(i=0;i<5;i++)//等待线程 
	{
		pthread_join(reader[i],NULL);
	}	
	
	sem_destroy(&rmutex);   //互斥锁的销毁
	sem_destroy(&wmutex);   
	sem_destroy(&mutex1);
	sem_destroy(&num);
	
	return 0;
} 

2.读者优先算法

为实现Reader和Writer进程之间在读或写时的互斥而设置了一个互斥信号量wmutex。再设置一个整型变量conut表示正在读的进程数目。

  • 仅当count=0时,Reader进程才需要执行wait(wmutex)操作;同理,仅当Reader进程在执行了count减一操作后其值为0时,才需要执行signal(wmutex)操作,以便让Writer进程操作;

  • 由于count是一个可被多个Reader进程访问的临界资源,因此为其设置一个互斥信号量rmutex;

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
 
#define N 5
 
int count=0,a=5,b=5;
int r[N]={0,1,2,3,4};
sem_t wmutex,rmutex;
 
 
void delay()
{
	int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒           
	usleep(time * 100000);
}
 
void Reader(void *arg)
{
	int i=*(int *)arg;
	while(a>0)
	{
    		a--;
    		delay();
        	sem_wait(&rmutex);
        	if(count==0)
        	    sem_wait(&wmutex);
        	count++;
        	sem_post(&rmutex);
	
        	printf("Reader%d is reading!\n",i);
        	printf("Reader%d reads end!\n",i);
        	
        	sem_wait(&rmutex);
        	count--;
        	if(count==0)
        	    sem_post(&wmutex);
        	sem_post(&rmutex);
    	}	
}
 
void Writer()
{
	while(b>0)
    	{
    		b--;
    		delay();
        	sem_wait(&wmutex);
    		
    		printf("writer is writing!\n");
        	printf("writer writes end!\n");
    		
        	sem_post(&wmutex);
    	}
}
 
int main()
{
	int i;
	pthread_t writer,reader[N];
	srand((unsigned int)time(NULL));
	
	sem_init(&wmutex,0,1);//互斥锁初始化 
	sem_init(&rmutex,0,1);
	
	for(i=0;i<5;i++)//创建线程 
	{
		pthread_create(&reader[i],NULL,(void *)Reader,&r[i]);
	} 
	
	pthread_create(&writer,NULL,(void *)Writer,NULL);
		
	pthread_join(writer,NULL);//线程等待 
	
	sem_destroy(&rmutex);   //互斥锁的销毁
	sem_destroy(&wmutex);   
	
	return 0;
} 

3.读写公平

为实现读写公平,我们必须要同时满足以下四个条件:

  • 读者写者的优先级相同
  • 读者、写者互斥访问
  • 只允许有一个写者访问临界区
  • 可以有多个读者同时访问临界区的资源
    为此,我们设置一个互斥信号量queue,其作用是让Writer进程和Reader进程进行排队,当有Reader进程执行时,queue=0,因此Writer进程会进入等待,直到queue变为1;当Writer进程执行时,同理;因此我们借助queue实现了读写进程的优先级平等。其余的和读者优选算法中相同。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
 
#define N 5
 
int readcount=0,a=5,b=5;
int r[N]={0,1,2,3,4};
sem_t wmutex,rmutex,queue;
 
 
void delay()
{
	int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒           
	usleep(time * 100000);
}
 
void Reader(void *arg)
{
	int i=*(int *)arg;
	while(a>0)
	{
    		a--;
    		delay();
    		
			sem_wait(&queue);		//让写者进程排队,读写进程具有相同的优先级 
        	sem_wait(&rmutex);		//与其他读者进程互斥的访问readcount 
        	if(readcount==0)		//最开始的时候readcount=0 
        		sem_wait(&wmutex);	//与写者进程互斥的访问共享文件 
        	readcount++;
        	sem_post(&rmutex);
			sem_post(&queue);		//使得写者进程进入准备状态 
	
			//Reader
        	printf("Reader%d is reading!\n",i);
        	printf("Reader%d reads end!\n",i);
        	
        	sem_wait(&rmutex);
        	readcount--;
        	if(readcount==0)
        	    sem_post(&wmutex);
        	sem_post(&rmutex);
    	}	
}
 
void Writer()
{
	while(b>0)
    	{
    		b--;
    		delay();
    		
    		sem_wait(&queue); 
        	sem_wait(&wmutex);
    		
    		printf("writer is writing!\n");
        	printf("writer writes end!\n");
    		
        	sem_post(&wmutex);
        	sem_post(&queue);
    	}
}
 
int main()
{
	int i;
	pthread_t writer,reader[N];
	srand((unsigned int)time(NULL));
	
	sem_init(&wmutex,0,1);//互斥锁初始化 
	sem_init(&rmutex,0,1);
	sem_init(&queue,0,1);
	
	for(i=0;i<5;i++)//创建线程 
	{
		pthread_create(&reader[i],NULL,(void *)Reader,&r[i]);
	} 
	
	pthread_create(&writer,NULL,(void *)Writer,NULL);
		
	pthread_join(writer,NULL);//线程等待 
	
	sem_destroy(&rmutex);   //互斥锁的销毁
	sem_destroy(&wmutex);   
	sem_destroy(&queue); 
	
	return 0;
} 

四、实验截图

1.写者优先算法

2.读者优先算法

3.读写公平

本文参考资料:
(35条消息) 经典的进程同步问题-----读者-写者问题详解_李子树_的博客-CSDN博客
https://blog.csdn.net/aimat2020/article/details/121692122

posted @ 2022-11-09 15:17  20201325my  阅读(315)  评论(0编辑  收藏  举报