操作系统--进程同步--读者写者问题

      用C语言编写和调试一个采用“读写平等”策略的“读者-写者”问题的模拟程序。利用模拟用信号量机制实现读者和写者问题:通过用户控制读进程和写进程,反应读者和写者问题中所涉及的进程的同步与互斥。

      要求实现:模拟用信号量机制实现读者和写者问题,即有两组并发进程:读者和写者,共享一组数据区,进行读写操作,要求任一时刻“写者”最多只允许一个,而“读者”则允许多个。

#include<stdio.h>

void write_p(int i);//模拟写者对Wmutex的P操作,同时也作为写者进程的入口
void write(int i);//开始写操作
void write_v(int i);//模拟写者对Wmutex的V操作,写操作完成的时候调用
void radd_p(int i);//模拟读之前对Rmutex的P操作,同时也作为读者进程的入口
void radd(int i);//Rcount加1
void read_p(int i);//模拟读者对Wmutex的P操作
void radd_v(int i);//模拟读之前对Rmutex的V操作
void read(int i);//读
void rsub_p(int i);//模拟读之后对Rmutex的P操作,读操作完成的时候调用
void rsub(int i);//Rcount减1
void read_v(int i);//模拟读者对Wmutex的V操作
void rsub_v(int i);//模拟读之后对Rmutex的V操作


int r_num;//读者个数
int w_num;//写者个数
int Wmutex=1;//表示允许写或允许读
int Rcount=0;//表示正在读的进程数
int Rmutex=1;//表示对Rcount的互斥操作
int r[10]={0,0,0,0,0,0,0,0,0,0};//表示读者的状态,1表示正在读
int w[10]={0,0,0,0,0,0,0,0,0,0};//表示写者的状态,1表示正在写
int w_wait[11]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};//表示等待队列,0-9表示写者,10时需引入读者的等待队列,-1表示空
int r_wait[11]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};//读者的等待队列,0-9表示对应的读者,-1为空

int main()
{
	printf("请输入写者个数(1到10):");
	scanf("%d",&w_num);
	while(w_num<1||w_num>10)
	{
		printf("输入有误,请重新输入写者个数(1到10):");
		scanf("%d",&w_num);
	}//完成对写者个数的输入
	
	printf("请输入读者个数(1到10):");
	scanf("%d",&r_num);
	while(w_num<1||w_num>10)
	{
		printf("输入有误,请重新输入读者个数(1到10):");
		scanf("%d",&r_num);
	}//完成对读者个数的输入

int x,k,j,a[20];
	while(1)
	{
		printf("************************************\n");
		for(k=0;k<20;k++) a[k]=0;
		printf("Wmutex=%d",Wmutex);
		printf("Rcount=%d",Rcount);
		printf("Rmutex=%d\n",Rmutex);

		for(k=0;k<w_num;k++)
		{
			if(w[k]==1)
				printf("-----写者%d正在写\n",(k+1));
		}
		for(k=0;k<r_num;k++)
		{
			if(r[k]==1)
				printf("-----读者%d正在读\n",(k+1));
		}
if(w_wait[0]==-1)printf("等待队列中无对象\n");
		else 
		{
			printf("等待队列中有");
			for(k=0;k<w_num;k++)
			{
				if(w_wait[k]==10)
					for(j=0;j<5;j++)
					{
						if(r_wait[j]!=-1)
							printf("-->读者%d\n",(r_wait[j]+1));
					}
					if((w_wait[k]>=0)&&(w_wait[k]<w_num))
						printf("-->写者%d\n",(r_wait[k]+1));
			}			
		}
		printf("\n");
			for(k=0;k<w_num;k++)
		{
			x=0;
			for(j=0;j<w_num;j++)
			{
				if(k==w_wait[j])
				{
					a[k]=1;
					x=1;
				}
			}
			if(x==1) continue;
			printf("(%d)写者%d",(k+1),(k+1));
			if(w[k]==0) printf("申请\n");
			else printf("完成\n");
		}
for(k=0;k<r_num;k++)
		{
			x=0;
			for(j=0;j<r_num;j++)
			{
				if(k==r_wait[j])
				{
					a[k+w_num]=1;
					x=1;
				}
			}
			if(x==1) continue;
			printf("(%d)读者%d",(k+1+w_num),(k+1));
			if(r[k]==0) printf("申请\n");
			else printf("完成\n");
		}
		printf("(%d)结束",(w_num+r_num+1));
		printf("请输入选项序号:");
		scanf("%d",&x); 
 
while(x<1||x>(w_num+r_num+1)||a[x-1]==1)
		{
			if(a[x-1]==1) printf("该对象已在等待队列中,请重新输入:");
			else 
			{
				printf("输入有误,请重新输入:");
				scanf("%d",&x);
			}
		}
		for(k=0;k<w_num;k++)
		{
			if(x==(k+1))
			{
				if(w[k]==0) write_p(k);
				else write_v(k);
				break;
			}
		}
		for(k=0;k<r_num;k++)
		{
			if(x==(k+1+w_num))
			{
				if(r[k]==0) radd_p(k);
				else rsub_p(k);
				break;
			}
		}
		if(x==(w_num+r_num+1)) return 0;
	}
}

//模拟写者对Wmutex的P操作,同时为写者进程也作写的入口:
void write_p(int i)
{
	Wmutex--;
	if(Wmutex<0)    // 表示如果Wmutex<0,则该写者进入等待队列
	{
		w_wait[-Wmutex-1]=i;
	}
	else
		write(i);
}
//进行写操作:
void write(int i)
{
	w[i]=1;
}
//模拟写者对Wmutex的V操作,写操作完成的时候调用:
void write_v(int i)
{
	w[i]=0;
	Wmutex++;
	if(Wmutex<=0)    //	表示如果Wmutex<=0,则从等待队列中选择写者或读者进行操作
	{
		int k,j;
		if((w_wait[0]>=0)&&(w_wait[0]<w_num))
		{
			j=w_wait[0];
			for(k=0;k<w_num;k++) w_wait[k]=w_wait[k+1];
			write(j);
		}
		else
		{		
			j=r_wait[0];
			for(k=0;k<w_num;k++) w_wait[k]=w_wait[k+1];
			for(k=0;k<r_num;k++) r_wait[k]=r_wait[k+1];
			radd_v(j);		
		}
	}
}
//模拟读之前对Rmutex的P操作,同时也作为读者进程的入口:
void radd_p(int i) {
	Rmutex--;
	if(Rmutex<0)        // 表示如果Rmutex<0,则进入等待队列
	{
		r_wait[-Rmutex]=i;
	}
	else
		radd(i);
}
//对于Rcount加1的控制:
void radd(int i)
{
	Rcount++;
	if(Rcount==1)
		read_p(i);
	else
		radd_v(i);
}
//模拟读者对Wmutex的P操作:
void read_p(int i)
{
	Wmutex--;
	if(Wmutex<0)      // 表示如果Wmutex<0,则进入等待队列
	{
		w_wait[-Wmutex-1]=10;
		r_wait[0]=i;
	}
	else
		radd_v(i);
}
//模拟读之前对Rmutex的V操作:
void radd_v(int i)
{
	Rmutex++;
	
	if(Rmutex<=0) // 表示如果Rmutex<=0,则从等待队列中选择读者进入Rcount的临界区
	{
		int k,j;
		j=r_wait[0];
		for(k=0;k<r_num;k++) r_wait[k]=r_wait[k+1];
		radd(j);
	}
	read(i);
}
//进行读操作:
void read(int i)
{
	r[i]=1;
}
//模拟读之后对Rmutex的P操作,读操作完成的时候调用:
void rsub_p(int i)    
{
	r[i]=0;
	Rmutex--;
	rsub(i);
}
//对Rcount减1的控制:
void rsub(int i)
{
	Rcount--;
	if(Rcount==0)
		read_v(i);
	else
		rsub_v(i);
}
//模拟读者对Wmutex的V操作:
void read_v(int i) {
	Wmutex++;
	if(Wmutex<=0)     //表示如果Wmutex<=0,则从等待队列中选择写者或读者进行操作
	{
		int k,j;
		if((w_wait[0]>=0)&&(w_wait[0]<w_num))
		{
			j=w_wait[0];
			for(k=0;k<w_num;k++) w_wait[k]=w_wait[k+1];
			write(j);
		}
		else
		{		
			j=r_wait[0];
			for(k=0;k<w_num;k++) w_wait[k]=w_wait[k+1];
			for(k=0;k<r_num;k++) r_wait[k]=r_wait[k+1];
			radd_v(j);		
		}
	}
	rsub_v(i);
}
//模拟读之后对Rmutex的V操作:
void rsub_v(int i)
{
	Rmutex++;
}

运行结果:

读写互斥

读读共享

写写互斥

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
读者写者问题是在多线程编程中经典的进程同步问题,主要涉及到两个角色:读者写者读者写者共享同一个资源,但是他们对于这个资源的访问方式是不同的。 在读者写者问题中,写者拥有独占的访问权,而读者可以共享访问权。同时,为了保证资源的完整性,读者写者之间必须进行同步。 下面是使用C++编程实现读者写者问题的示例代码: ```cpp #include <iostream> #include <thread> #include <mutex> #include <condition_variable> using namespace std; mutex mtx; condition_variable cv; int resource = 0; int reader_count = 0; void reader(int id) { unique_lock<mutex> lock(mtx); cout << "Reader " << id << " is waiting..." << endl; cv.wait(lock, []{return reader_count == 0;}); reader_count++; lock.unlock(); // 读取资源 cout << "Reader " << id << " is reading resource: " << resource << endl; lock.lock(); reader_count--; if (reader_count == 0) { cv.notify_one(); } lock.unlock(); } void writer(int id) { unique_lock<mutex> lock(mtx); cout << "Writer " << id << " is waiting..." << endl; cv.wait(lock, []{return reader_count == 0;}); // 写入资源 resource++; cout << "Writer " << id << " is writing resource: " << resource << endl; cv.notify_all(); lock.unlock(); } int main() { thread readers[5], writers[2]; for (int i = 0; i < 5; i++) { readers[i] = thread(reader, i); } for (int i = 0; i < 2; i++) { writers[i] = thread(writer, i); } for (int i = 0; i < 5; i++) { readers[i].join(); } for (int i = 0; i < 2; i++) { writers[i].join(); } return 0; } ``` 在这个例子中,我们使用了一个互斥锁和条件变量来实现读者写者之间的同步。读者写者都必须获得互斥锁才能访问共享资源,并且读者写者之间需要通过条件变量进行通信。 在读者函数中,读者必须等待所有的写者完成工作,并且没有其他读者正在访问资源,才能够开始读取资源。在写者函数中,写者必须等待所有的读者完成工作,才能够开始写入资源。同时,写者在写入资源之后需要通知所有等待的读者写者。 这个例子中的读者写者都是通过创建线程来模拟的。您可以根据自己的需要调整线程的数量和资源的访问方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值