用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++;
}
运行结果:
读写互斥
读读共享
写写互斥