《操作系统》课程设计报告.docx
- 文档编号:25921556
- 上传时间:2023-06-16
- 格式:DOCX
- 页数:32
- 大小:23.35KB
《操作系统》课程设计报告.docx
《《操作系统》课程设计报告.docx》由会员分享,可在线阅读,更多相关《《操作系统》课程设计报告.docx(32页珍藏版)》请在冰豆网上搜索。
《操作系统》课程设计报告
《操作系统》课程设计报告
一、读者/写者的问题模拟实现
读者/写者问题,是指保证一个writer进程必须与其他进程互斥地访问共享对象的同步问题。
读者写者问题可以这样的描述:
有一群写者和一群读者,写者在写同一本书,读者也在读这本书,多个读者可以同时读这本书,但是只能有一个写者在写书,并且读者必优先,也就是说,读者和写者同时提出请求时,读者优先。
当读者提出请求时,需要有一个互斥操作,另外需要有一个信号量S来确定当前是否可操作。
信号量机制是支持多道程序的并发操作系统设计中解决资源共享时进程间的同步与互斥的重要机制,而读者写者则是这一机制的一个经典范例。
与记录型信号量解决读者——写者问题不同,信号量机制它增加了一个限制,即最多允许RN个读者同时读。
为此,又引入了一个信号量L,并赋予初值为RN,通过执行wait(L,1,1)操作来控制读者的数目,每当有一个读者进入时,就要执行wait(L,1,1)操作,使L的值减1。
当有RN个读者进入读后,L便减为0,第RN+1个读者要进入读时,必然会因wait(L,1,1)操作失败而堵塞。
程序实例:
#include
#include
#include
#include
#include
#include
#defineMAX_PERSON100
#defineREADER0//读者
#defineWRITER1//写者
#defineEND-1
#defineRREADER
#defineWWRITER
typedefstruct_Person
{
HANDLEm_hThread;//定义处理线程的句柄
intm_nType;//进程类型(读写)
intm_nStartTime;//开始时间
intm_nWorkTime;//运行时间
intm_nID;//进程号
}Person;
Persong_Persons[MAX_PERSON];
intg_NumPerson=0;
longg_CurrentTime=0;//基本时间片数
intg_PersonLists[]={//进程队列
1,W,3,5,2,W,16,5,3,R,5,2,
4,W,6,5,5,R,4,3,6,R,17,7,
END,
};
intg_NumOfReading=0;
intg_NumOfWriteRequest=0;//申请写进程的个数
HANDLEg_hReadSemaphore;//读者信号
HANDLEg_hWriteSemaphore;//写者信号
boolfinished=false;//所有的读完成
//boolwfinished=false;//所有的写完成
voidCreatePersonList(int*pPersonList);
boolCreateReader(intStartTime,intWorkTime,intID);
boolCreateWriter(intStartTime,intWorkTime,intID);
DWORDWINAPIReaderProc(LPVOIDlpParam);
DWORDWINAPIWriterProc(LPVOIDlpParam);
intmain()
{
g_hReadSemaphore=CreateSemaphore(NULL,1,100,NULL);//创建信号灯,当前可用的资源数为1,最大为100
g_hWriteSemaphore=CreateSemaphore(NULL,1,100,NULL);//创建信号灯,当前可用的资源数为1,最大为100
CreatePersonList(g_PersonLists);//CreateAllthereaderandwriters
printf("Createdallthereaderandwriter\n创建\n");
g_CurrentTime=0;
while(true)
{
g_CurrentTime++;
Sleep(300);//300ms
printf("CurrentTime=%d\n",g_CurrentTime);
if(finished)return0;
}//return0;
}
voidCreatePersonList(int*pPersonLists)
{
inti=0;
int*pList=pPersonLists;
boolRet;
while(pList[0]!
=END)
{
switch(pList[1])
{
caseR:
Ret=CreateReader(pList[2],pList[3],pList[0]);//351,w452,523,654
break;caseW:
Ret=CreateWriter(pList[2],pList[3],pList[0]);
break;
}
if(!
Ret)
printf("CreatePerson%diswrong\n",pList[0]);
pList+=4;//movetonextpersonlist
}
}
DWORDWINAPIReaderProc(LPVOIDlpParam)//读过程
{
Person*pPerson=(Person*)lpParam;
//waitforthestarttime
while(g_CurrentTime!
=pPerson->m_nStartTime)
{}
printf("Reader%disRequesting等待\n",pPerson->m_nID);
printf("\n\n************************************************\n");
//waitforthewriterequest
WaitForSingleObject(g_hReadSemaphore,INFINITE);if(g_NumOfReading==0)
{
WaitForSingleObject(g_hWriteSemaphore,INFINITE);}
g_NumOfReading++;
ReleaseSemaphore(g_hReadSemaphore,1,NULL);
pPerson->m_nStartTime=g_CurrentTime;
printf("Reader%disReadingtheSharedBuffer等待\n",pPerson->m_nID);
printf("\n\n************************************************\n");
while(g_CurrentTime<=pPerson->m_nStartTime+pPerson->m_nWorkTime)
{}
printf("Reader%disExit退出\n",pPerson->m_nID);
printf("\n\n************************************************\n");
WaitForSingleObject(g_hReadSemaphore,INFINITE);
g_NumOfReading--;
if(g_NumOfReading==0)
{ReleaseSemaphore(g_hWriteSemaphore,1,NULL);//此时没有读者,可以写
}
ReleaseSemaphore(g_hReadSemaphore,1,NULL);
if(pPerson->m_nID==4)finished=true;//所有的读写完成
ExitThread(0);
return0;
}
DWORDWINAPIWriterProc(LPVOIDlpParam)
{
Person*pPerson=(Person*)lpParam;
//waitforthestarttime
while(g_CurrentTime!
=pPerson->m_nStartTime)
{}
printf("Writer%disRequesting请求进行写操作\n",pPerson->m_nID);
printf("\n\n************************************************\n");
WaitForSingleObject(g_hWriteSemaphore,INFINITE);
//modifythewriter'srealstarttime
pPerson->m_nStartTime=g_CurrentTime;
printf("Writer%disWrittingtheSharedBuffer写内容\n",pPerson->m_nID);
while(g_CurrentTime<=pPerson->m_nStartTime+pPerson->m_nWorkTime)
{}
printf("Writer%disExit退出\n",pPerson->m_nID);
printf("\n\n************************************************\n");
//g_NumOfWriteRequest--;
ReleaseSemaphore(g_hWriteSemaphore,1,NULL);
if(pPerson->m_nID==4)finished=true;//所有的读写完成
ExitThread(0);
return0;
}
boolCreateReader(intStartTime,intWorkTime,intID)
{
DWORDdwThreadID;
if(g_NumPerson>=MAX_PERSON)
returnfalse;
Person*pPerson=&g_Persons[g_NumPerson];
pPerson->m_nID=ID;
pPerson->m_nStartTime=StartTime;
pPerson->m_nWorkTime=WorkTime;
pPerson->m_nType=READER;
g_NumPerson++;
//CreateanNewThread
pPerson->m_hThread=CreateThread(NULL,0,ReaderProc,(LPVOID)pPerson,0,&dwThreadID);
if(pPerson->m_hThread==NULL)
returnfalse;
returntrue;
}
boolCreateWriter(intStartTime,intWorkTime,intID)
{
DWORDdwThreadID;
if(g_NumPerson>=MAX_PERSON)
returnfalse;
Person*pPerson=&g_Persons[g_NumPerson];
pPerson->m_nID=ID;
pPerson->m_nStartTime=StartTime;
pPerson->m_nWorkTime=WorkTime;
pPerson->m_nType=WRITER;
g_NumPerson++;
//CreateanNewThread
pPerson->m_hThread=CreateThread(NULL,0,WriterProc,(LPVOID)pPerson,0,&dwThreadID);
if(pPerson->m_hThread==NULL)
returnfalse;
returntrue;
}
二、进程间通信与子进程
使用管道进行父子进程间通信,程序首先判断参数是否合法,因为输入的字符将从父进程通过发送到子进程中。
然后调用pipe函数创建父子进程用于通信的管道。
使用fork函数创建子进程时,子进程会获得与父进程相同的资源,其中包括文件描述符信息。
因此,调用fork函数须在pipe函数调用前。
当父子进程通过管道进行通信时,files[1]为用于数据写入的文件描述符.因此,在子进程中,要读取管道中的数据可以调用read函数,而读取得文件描述符为files[0]。
对于父进程而言,写入数据需要调用write函数,要写入的文件描述为files[1]。
程序代码:
#include
#include
intmain(intargc,char*argv[])
{
intf_des[2];
intpid;
charmsg[BUFSIZ];
if(argc!
=2){
printf("Usage:
%smessage\n",argv[0]);
return1;
}
if(pipe(f_des)==-1){
perror("cannotcreatetheIPCpipe");
return1;
}
pid=fork();
if(pid==-1){
perror("cannotcreatenewprocess");
return1;
}elseif(pid==0){
close(f_des[1]);
if(read(f_des[0],msg,BUFSIZ)==-1){
perror("childprocesscannotreaddatafrompipe");
return1;
}else
printf("inchildprocess,receivemessage:
%s\n",msg);
_exit(0);
}else{
close(f_des[0]);
if(write(f_des[1],argv[1],strlen(argv[1]))==-1){
perror("parentprocesscannotwritedatatopipe");
return1;
}else
printf("inparentprocess,sendmessage:
%s\n",argv[1]);
wait(NULL);
_exit(0);
}
return0;
}
三、进程多级调度模拟
1.设置多个就绪队列,并给队列赋予不同的优先级数,第一个最高,依次递减。
2.赋予各个队列中进程执行时间片的大小,优先级越高的队列,时间片越小。
3.当一个新进程进入内存后,首先将其放入一个对列末尾,如果在一个时间片
结束时尚未完成,将其转入第二队列末尾。
4.当一个进程从一个对列移至第n个队列后,便在第n个队列中采用时间片轮转执行完。
5.仅当时间片空闲时,才调度第二个队列中的进程。
(1~i-1)空闲时,才调度i,如果处理机正在第i队列中运行,又有新进程进入优先权较高
队列,则新进程抢占处理机,将正在运行的进程放入第i队列队尾,将处理机分给新进程。
程序代码:
#include
#include
#include
typedefstructnode/*进程节点信息*/
{
charname[20];/*进程的名字*/
intprio;/*进程的优先级*/
intround;/*分配CPU的时间片*/
intcputime;/*CPU执行时间*/
intneedtime;/*进程执行所需要的时间*/
charstate;/*进程的状态,W——就绪态,R——执行态,F——完成态*/
intcount;/*记录执行的次数*/
structnode*next;/*链表指针*/
}PCB;
typedefstructQueue/*多级就绪队列节点信息*/
{
PCB*LinkPCB;/*就绪队列中的进程队列指针*/
intprio;/*本就绪队列的优先级*/
intround;/*本就绪队列所分配的时间片*/
structQueue*next;/*指向下一个就绪队列的链表指针*/
}ReadyQueue;
PCB*run=NULL,*finish=NULL;/*定义三个队列,就绪队列,执行队列和完成队列*/
ReadyQueue*Head=NULL;/*定义第一个就绪队列*/
intnum;/*进程个数*/
intReadyNum;/*就绪队列个数*/
voidOutput();/*进程信息输出函数*/
voidInsertFinish(PCB*in);/*将进程插入到完成队列尾部*/
voidInsertPrio(ReadyQueue*in);/*创建就绪队列,规定优先数越小,优先级越低*/
voidPrioCreate();/*创建就绪队列输入函数*/
voidGetFirst(ReadyQueue*queue);/*取得某一个就绪队列中的队头进程*/
voidInsertLast(PCB*in,ReadyQueue*queue);/*将进程插入到就绪队列尾部*/
voidProcessCreate();/*进程创建函数*/
voidRoundRun(ReadyQueue*timechip);/*时间片轮转调度算法*/
voidMultiDispatch();/*多级调度算法,每次执行一个时间片*/
intmain(void)
{
PrioCreate();/*创建就绪队列*/
ProcessCreate();/*创建就绪进程队列*/
MultiDispatch();/*算法开始*/
Output();/*输出最终的调度序列*/
return0;
}
voidOutput()/*进程信息输出函数*/
{
ReadyQueue*print=Head;
PCB*p;
printf("进程名\t优先级\t轮数\tcpu时间\t需要时间\t进程状态\t计数器\n");
while(print)
{
if(print->LinkPCB!
=NULL)
{
p=print->LinkPCB;
while(p)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p=p->next;
}
}
print=print->next;
}
p=finish;
while(p!
=NULL)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p=p->next;
}
p=run;
while(p!
=NULL)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p=p->next;
}
}
voidInsertFinish(PCB*in)/*将进程插入到完成队列尾部*/
{
PCB*fst;
fst=finish;
if(finish==NULL)
{
in->next=finish;
finish=in;
}
else
{
while(fst->next!
=NULL)
{
fst=fst->next;
}
in->next=fst->next;
fst->next=in;
}
}
voidInsertPrio(ReadyQueue*in)/*创建就绪队列,规定优先数越小,优先级越低*/
{
ReadyQueue*fst,*nxt;
fst=nxt=Head;
if(Head==NULL)/*如果没有队列,则为第一个元素*/
{
in->next=Head;
Head=in;
}
else/*查到合适的位置进行插入*/
{
if(in->prio>=fst->prio)/*比第一个还要大,则插入到队头*/
{
in->next=Head;
Head=in;
}
else
{
while(fst->next!
=NULL)/*移动指针查找第一个别它小的元素的位置进行插入*/
{
nxt=fst;
fst=fst->next;
}
if(fst->next==NULL)/*已经搜索到队尾,则其优先级数最小,将其插入到队尾即可*/
{
in->next=fst->next;
fst->next=in;
}
else/*插入到队列中*/
{
nxt=in;
in->next=fst;
}
}
}
}
voidPrioCreate()/*创建就绪队列输入函数*/
{
ReadyQueue*tmp;
inti;
printf("输入就绪队列的个数:
\n");
scanf("%d",&ReadyNum);
printf("输入每个就绪队列的CPU时间片:
\n");
for(i=0;i { if((tmp=(ReadyQueue*)malloc(sizeof(ReadyQueue)))==NULL) { perror("malloc"); exit (1); } scanf("%d",&(tmp->round));/*输入此就绪队列中给每个进程所分配的CPU
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 课程设计 报告