问题描述:
所谓读者写着问题,是指保证一个writer进程必须与其他进程互斥地访问共享对象的同步问题。读者写者问题可以这样的描述,有一群写者和一群读者,写者在写同一本书,读者也在读这本书,多个读者可以同时读这本书,但是,只能有一个写者在写书。为实现读写同步,需要使用信号量机制。信号量机制是支持多道程序的并发操作系统设计中解决资源共享时进程间的同步与互斥的重要机制,而读者写者则是这一机制的一个经典范例。
对利用信号量来解决读者—写者问题的描述如下:
1)写-写互斥,即不能有两个写者同时进行写操作;
2)读-写互斥,即不能同时有一个读者在读,同时却有一个写者在写;
3)读读允许,即可以有2个以上的读者同时读。
课设要求:
本次课程设计中,在处理读者写者等待队列的请求时,用到了两种唤醒进程算法:读者优先唤醒算法和写者优先唤醒算法。
读优先:当一个读者与若干写者同时处于等待队列中时,并且此时并无写操作进行时,读者优先进行读。
写优先:当一个读者与若干写者同时处于等待队列中时,并且此时并无写操作进行时,写者优先进行写。
主要数据结构:
typedef struct
{
int id;
char name[256];
int operateTime;
int flag;//1为读者,2为写者
}runQueue;//进行中队列结构;
typedef struct
{
int id;
char name[256];
int operatetime;
int flag;//1为读等待,2为写等待
}wait;//等待队列结构;
个人思路:
创建两个队列,一个队列用于存储进行中的进程;一个队列用于存储等待中的进程。当创建读者进程或写者进程时,查看当前进行中队列是否已满,若已满则进入等待者队列。当一个进程结束时,查看其是否占用队列最后一位,若是则等待中队列进程可进入进行中队列。在单个进程对队列操作时,对队列使用p操作,结束后使用v操作释放。
环境:
编译器:codeblocks20.03
c语言:c11
操作系统:windows10
代码:
主函数以及各定义
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string.h>
typedef struct
{
int id;
char name[256];
int operateTime;
int flag;//1为读者,2为写者
}runQueue;//进行中队列结构;
typedef struct
{
int id;
char name[256];
int operatetime;
int flag;//1为读等待,2为写等待
}wait;//等待队列结构;
int id = 0;//全局变量id
int waitqLen=0,runqLen=0; //全局变量三个队列的长度
int waitqNLen=0,runqNLen=0; //全局变量三个队列目前的长度
int nowThread = 0;//目前线程数
int operating1 = 0,operating2 = 0;//正在对队列操作的进程
wait waitQueue[1000]={}; //等待者队列
runQueue runningQueue[1000]={};//进行中队列
void showQueue();//展示目前队列情况
void creatReader();//创建读者
void creatWriter();//创建写者
void readerThread();//读者线程
void writerThread();//写者线程
void WaitToRun();//等待队列进入进行中队列(读者优先)
void WaitToRunWFirst();//等待队列进入进行中队列(写者优先)
void runWaitToRun();//进入队列线程开启
void AreaderThread();//单个读者线程
void AwriterThread();//单个写者线程
int main()
{
printf("请输入等待队列长度:");
scanf("%d",&waitqLen);
printf("请输入进行中队列长度:");
scanf("%d",&runqLen);
int Choice = 0;
while(1)
{
Choice=0;
printf("1.查看当前队列情况\n");
printf("2.创建读者\n");
printf("3.创建写者\n");
printf("4.退出\n");
printf("请输入操作项:");
scanf("%d",&Choice);
switch(Choice)
{
case 1:
showQueue();
break;
case 2:
creatReader();
break;
case 3:
creatWriter();
break;
case 4:
return 0;
break;
}
}
}
展示目前队列
void showQueue()
{
printf("\n/****---------------------****/\n");
printf("当前进程数:%d\n\n",nowThread);
printf("等待者队列:\n");
for(int i=1;i<=waitqNLen;i++)
{
printf("/**\n等待者id:%d\n",waitQueue[i].id);
printf("等待者名:%s\n",waitQueue[i].name);
if(waitQueue[i].flag==1)
printf("等待者类型:读者\n");
else
printf("等待者类型:写者\n");
printf("等待者操作时间:%ds\n**/\n",waitQueue[i].operatetime);
}
printf("---------------------\n");
printf("进行中队列:\n");
for(int i=1;i<=runqNLen;i++)
{
if(runningQueue[i].flag==1)
{
printf("/**\n读者id:%d\n",runningQueue[i].id);
printf("读者名:%s\n**/\n",runningQueue[i].name);
}
else
{
printf("/**\n写者id:%d\n",runningQueue[i].id);
printf("写者名:%s\n**/\n",runningQueue[i].name);
}
}
printf("\n/****---------------------****/\n\n");
}
创建读者、写者
void creatReader()
{
if(runqNLen == runqLen || runningQueue[0].flag==2)
{
printf("当前进行中队列已满,进入等待队列。\n");
if(waitqNLen == waitqLen)
{
printf("等待队列已满,入队失败!\n");
}
else
{
id++;
waitqNLen++;
waitQueue[waitqNLen].id=id;
printf("请输入读者名:");
scanf("%s",waitQueue[waitqNLen].name);
waitQueue[waitqNLen].flag=1;
printf("请输入读时间:");
scanf("%d",&waitQueue[waitqNLen].operatetime);
printf("已进入等待队列。\n");
return 0;
}
return 0;
}
else
{
id++;
int readtime=0;
runqNLen++;
runningQueue[runqNLen].id=id;
printf("请输入读者名:");
scanf("%s",runningQueue[runqNLen].name);
runningQueue[runqNLen].flag = 1;
printf("请输入阅读时间(单位:秒):");
scanf("%d",&readtime);
runningQueue[runqNLen].operateTime=readtime;
printf("开启读者线程成功,读者id:%d,读者名称%s\n",id,runningQueue[runqNLen].name);
_beginthread(readerThread,0,NULL);
nowThread++;
}
}
void creatWriter()
{
if(runqNLen != 0)
{
printf("当前进行中队列已满,进入等待队列。\n");
if(waitqNLen == waitqLen)
{
printf("等待队列已满,入队失败!\n");
}
else
{
id++;
waitqNLen++;
waitQueue[waitqNLen].id=id;
printf("请输入读者名:");
scanf("%s",waitQueue[waitqNLen].name);
waitQueue[waitqNLen].flag=2;
printf("请输入读时间:");
scanf("%d",&waitQueue[waitqNLen].operatetime);
printf("已进入等待队列。\n");
return 0;
}
return 0;
}
else
{
id++;
int readtime=0;
runqNLen++;
runningQueue[runqNLen].id=id;
printf("请输入写者名:");
scanf("%s",runningQueue[runqNLen].name);
runningQueue[runqNLen].flag = 2;
printf("请输入写作时间(单位:秒):");
scanf("%d",&readtime);
runningQueue[runqNLen].operateTime=readtime;
printf("开启写者线程成功,写者id:%d,写者名称%s\n",id,runningQueue[runqNLen].name);
_beginthread(writerThread,0,NULL);
nowThread++;
}
}
等待队列进入/读者优先/
void WaitToRun()
{
if(waitqNLen==0)
return 0;
else
{
while(1)
{
if(operating1==0)
break;
Sleep(200);
}
operating1=1;
for(int i = 1;i<=waitqNLen;i++)
{
if(waitQueue[i].flag == 1)
{
while(1)
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
runqNLen++;
runningQueue[runqNLen].flag=waitQueue[i].flag;
runningQueue[runqNLen].id=waitQueue[i].id;
strcpy(runningQueue[runqNLen].name,waitQueue[i].name);
runningQueue[runqNLen].operateTime=waitQueue[i].operatetime;
printf("开启读者线程成功,读者id:%d,读者名称%s\n",runningQueue[runqNLen].id,runningQueue[runqNLen].name);
_beginthread(AreaderThread,0,NULL);
operating2=0;
for(int j = i;j<=waitqNLen;j++)
{
waitQueue[j]=waitQueue[j+1];
}
waitqNLen--;
operating1=0;
return 0;
}
operating1=0;
if(i==waitqNLen&&runqNLen==0)
{
while(1)
{
if(operating1==0)
break;
Sleep(200);
}
operating1=1;
for(i=1;i<=waitqNLen;i++)
{
if(waitQueue[i].flag == 2)
{
while(1)
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
runqNLen++;
runningQueue[runqNLen].flag=waitQueue[i].flag;
runningQueue[runqNLen].id=waitQueue[i].id;
strcpy(runningQueue[runqNLen].name,waitQueue[i].name);
runningQueue[runqNLen].operateTime=waitQueue[i].operatetime;
printf("开启写者线程成功,写者id:%d,写者名称%s\n",runningQueue[runqNLen].id,runningQueue[runqNLen].name);
_beginthread(AwriterThread,0,NULL);
operating2=0;
for(int j = i;j<=waitqNLen;j++)
{
waitQueue[j]=waitQueue[j+1];
}
waitqNLen--;
operating1=0;
return 0;
}
}
operating1=0;
return 0;
}
}
}
}
等待队列进入/写者优先/
/*写者优先*/
void WaitToRunWFirst()
{
if (waitqNLen == 0)
return 0;
else
{
while (1)
{
if (operating1 == 0)
break;
Sleep(200);
}
operating1 = 1;
for (int i = 1; i <= waitqNLen; i++)
{
if (waitQueue[i].flag == 2)
{
while (1)
{
if (operating2 == 0)
break;
Sleep(200);
}
operating2 = 1;
runqNLen++;
runningQueue[runqNLen].flag = waitQueue[i].flag;
runningQueue[runqNLen].id = waitQueue[i].id;
strcpy(runningQueue[runqNLen].name, waitQueue[i].name);
runningQueue[runqNLen].operateTime = waitQueue[i].operatetime;
printf("开启读者线程成功,读者id:%d,读者名称%s\n", runningQueue[runqNLen].id, runningQueue[runqNLen].name);
_beginthread(AreaderThread, 0, NULL);
operating2 = 0;
for (int j = i; j <= waitqNLen; j++)
{
waitQueue[j] = waitQueue[j + 1];
}
waitqNLen--;
operating1 = 0;
return 0;
}
operating1 = 0;
if (i == waitqNLen)
{
while (1)
{
if (operating1 == 0)
break;
Sleep(200);
}
operating1 = 1;
for (i = 1; i <= waitqNLen; i++)
{
if (waitQueue[i].flag == 1)
{
while (1)
{
if (operating2 == 0)
break;
Sleep(200);
}
operating2 = 1;
runqNLen++;
runningQueue[runqNLen].flag = waitQueue[i].flag;
runningQueue[runqNLen].id = waitQueue[i].id;
strcpy(runningQueue[runqNLen].name, waitQueue[i].name);
runningQueue[runqNLen].operateTime = waitQueue[i].operatetime;
printf("开启写者线程成功,写者id:%d,写者名称%s\n", runningQueue[runqNLen].id, runningQueue[runqNLen].name);
_beginthread(AwriterThread, 0, NULL);
operating2 = 0;
for (int j = i; j <= waitqNLen; j++)
{
waitQueue[j] = waitQueue[j + 1];
}
waitqNLen--;
operating1 = 0;
return 0;
}
}
operating1 = 0;
return 0;
}
}
}
}
进程的内操作
void AreaderThread()
{
nowThread++;
int threadID=runningQueue[runqNLen].id;
Sleep(1000*runningQueue[runqNLen].operateTime);
while(1)//当有线程在操作队列时等待其操作结束才能开始操作
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
for(int i=1;i<=runqNLen;i++)
{
if(runningQueue[i].id==threadID)
{
printf("\n读者线程结束,读者id:%d,读者名称:%s\n",runningQueue[i].id,runningQueue[i].name);
for(int j = i;j<=runqNLen;j++)
{
runningQueue[j]=runningQueue[j+1];
}
runqNLen--;
break;
}
}
operating2=0;
WaitToRun();
nowThread--;
_endthread();
}
void AwriterThread()//单个写者线程
{
nowThread++;
int threadID=runningQueue[runqNLen].id;
Sleep(1000*runningQueue[runqNLen].operateTime);
while(1)//当有线程在操作队列时等待其操作结束才能开始操作
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
for(int i=1;i<=runqNLen;i++)
{
if(runningQueue[i].id==threadID)
{
printf("\n写者线程结束,写者id:%d,写者名称:%s\n",runningQueue[i].id,runningQueue[i].name);
for(int j = i;j<=runqNLen;j++)
{
runningQueue[j]=runningQueue[j+1];
}
runqNLen--;
break;
}
}
operating2=0;
nowThread--;
WaitToRun();
_endthread();
}
void writerThread()
{
int threadID=id;
Sleep(1000*runningQueue[runqNLen].operateTime);
while(1)//当有线程在操作队列时等待其操作结束才能开始操作
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
for(int i=1;i<=runqNLen;i++)
{
if(runningQueue[i].id==threadID)
{
printf("\n写者线程结束,写者id:%d,写者名称:%s\n",runningQueue[i].id,runningQueue[i].name);
for(int j = i;j<=runqNLen;j++)
{
runningQueue[j]=runningQueue[j+1];
}
runqNLen--;
break;
}
}
operating2=0;
nowThread--;
WaitToRun();
_endthread();
}
void readerThread()
{
int threadID=id;
Sleep(1000*runningQueue[runqNLen].operateTime);
while(1)
{
if(operating2==0)
break;
Sleep(200);
}
operating2=1;
for(int i=1;i<=runqNLen;i++)
{
if(runningQueue[i].id==threadID)
{
printf("\n读者线程结束,读者id:%d,读者名称:%s\n",runningQueue[i].id,runningQueue[i].name);
for(int j = i;j<=runqNLen;j++)
{
runningQueue[j]=runningQueue[j+1];
}
runqNLen--;
break;
}
}
operating2=0;
nowThread--;
WaitToRun();
_endthread();
}