这是大三做的一次作业,费了不少心血。
作业题目如下:
操作系统作业题目与要求
(2008.06)
一、 题 目
使用线程模拟 进程调度
1 .模拟进程调度具有的基本功能
(1)
按下面的进程状态变换图调度进程
( 2 )用户进程来自文件,每个文件表示一个用户进程,进程文件的格式如下:
C 100
I 50
O 30
C 200
O 20
1 )该虚拟进程表示的含义是:先在 CPU 上计算 100 秒,再在输入设备上输入数据 50 秒,输出 30 秒,再计算 200 秒,最后在输出设备上输入 20 秒,进程结束。
2 )字母表示进程要进行计算、输入和输出,后面的数字表示相应操作的时间单位。用户进程具体执行步骤和每一步需要的时间自己设定。
2 )要求该实验中至少有 10 个用户进程文件 PRO1 , PRO2 , ….. , PRO10 。
( 3 ) 按时间片轮转方法进行进程调度,时间片自己设定。调度时按先来先服务 和优先级策略选择用户进程执行。
( 4 ) 模拟时设置四个线程模块 , 分别是进程创建模块 PRO_CREATE 、进程执行模块 PRO_EXEC 、进程完成 I/O 操作模块 PRO_IO ,和进程撤消模块 PRO_EXIT 。并按就绪、等待和执行形成三个进程状态队列。
该实验必须用线程实现(线程部分参考有关编程书籍)。
( 5 ) 要求使用进程控制块 PCB ,使用作业表(可以参考教材内容设置必要的信息)
( 6 ) 实验输出包含两个部分:
1) ①输出执行每个用户进程的时间(由于使用时间片,一个进程可能需要多个时间片来完成,因此在输出时,这个进程的两次执行之间可能有其它进程),假如时间片为50 ,则输出可能是:
pro1 50 (说明:用户进程1 执行了一个时间片)
pro2 50 (说明:用户进程2 执行了一个时间片)
pro3 50 (说明:用户进程3 执行了一个时间片)
pro4 30( 说明:该进程执行30 就要求I/O ,因此调度下一个进程执行)
…
pro1 50 (说明:用户进程1 执行了下一个时间片)
…
②输入/ 输出线程为进程提供服务的进程名字和时间,例如:
pro1 10
pro2 40
pro3 20
…
pro2 10
…
2) 每个用户进程从开始到完成的每一步的起始时间,结束时间,如:
pro1:I 执行 开始时间1 结束时间1
执行 开始时间2 结束时间2
输入/ 输出 开始时间3 ,结束时间3
执行时间4 结束时间4
…
pro2:…
2 .选用程序设计语言: C ++、 C 等。
二、作业需提交内容:
1 .通过邮件将已调试通过的完整的模拟程序及运行需要的数据和执行结果发给老师,在适当机会抽查,并要求学生回答有关问题。( zmr15@tongji.mail.edu.cn )
2 .提交“课程设计说明书”,其内容详见下面“作业说明书的要求”;
3 .提交时间:在期末前三天内。
三、作业应具有的内容及其参考评分标准:
( 1 )设计思想说明( 5 分);
( 2 )所设计的系统结构的说明( 15 分);
( 3 )数据结构的说明( 5 分);
( 4 )各模块的算法流程图( 5 分);
( 5 )程序清单:格式规范,注意加注释(包含关键字、方法、变量等),在每个模块前加注释,注释不得少于 20% ;(共 60 分)
( 6 )使用说明书(即用户手册)( 5 分)
( 7 )体会,建议( 5 分)
四、注意事项
1 .按“作业需提交内容”提交完整的相关设计资料。
2 .严禁抄袭,复制设计内容,查出后相关同学设计成绩以零分处理。
3 .所提交源程序应是能够运行通过的完整程序。发邮件的时候不要重复发,打包是不要包含 OBJ 文件和无关文件,否则发送的内容太多。邮件主题用学号+姓名
五、提示
用户进程以文本文件的形式保存磁盘上,创建线程模块读文件并为每个文件建立 PCB ,再填入适当数据,这样就有了初始用户进程,并且这些用户进程在就绪队列。
建立三个队列:就绪、执行和等待。
建立执行线程模块,按先来先服务、时间片轮转方法进行调度。输入 / 输出线程模块完成 I/O 。
三个线程并发执行,根据队列和当前状态为作业提供服务。
#include <iostream>
#include <windows.h>
#include <fstream>
#include <conio.h>
#include <time.h>
#define timepiece 10000 //时间片 10s
#define SIZE 10 //用户进程个数
using namespace std;
typedef struct pcb
{
char name[10];
char status; //进程状态:running、wait、ready(,w,r)
int priority; //1-7,越高越优先
int progress; //进程完成进度1.C 100 /2.I 50 /3.O 30 /4.C 200 /5.O 20 /0.尚未执行
int progressFinished; //每块完成情况 0:尚未执行
struct pcb *next; //指向下一个pcb地址
struct pcb *all_q_next;
int time; //等待时间
}PCB;
/*PCB *ready=NULL,*wait=NULL; */ //就绪、等待队列
//等待队列究竟是否有用?一个是计算,一个是IO,不如设一个计算就绪队列,等待计算;一个IO就绪队列,等待IO
PCB *ready_calculate=NULL,*ready_io=NULL;
//再搞个死亡队列吧。。。运行结束的程序都放到这里来。。其实个人感觉可以不要的,只是为了进程撤销模块
PCB *death=NULL;
//计算和IO的线程还活着米?抑或是死了?Java里面有isAlive()判断线程是否还在运行,可惜C++貌似没有额,大概是我没找到吧
int CalculateIsAlive=1,IOIsAlive=1;
//第四步做完,计算就再也没有用了;第五步做完,IO就再也没有用了
int finish4=0,finish5=0;
DWORD WINAPI pro_create(LPVOID lpParameter);
DWORD WINAPI pro_execute(LPVOID lpParameter);
DWORD WINAPI pro_io(LPVOID lpParameter);
DWORD WINAPI pro_exit(LPVOID lpParameter);
HANDLE hMutex=CreateMutex(NULL,FALSE,NULL);
//void open(PCB *&ready);
//void run(PCB *&ready);
void main()
{
HANDLE create;
HANDLE execute;
HANDLE io;
HANDLE exit;
ready_calculate=(PCB *)malloc(sizeof(PCB));
ready_io=(PCB *)malloc(sizeof(PCB));
death=(PCB *)malloc(sizeof(PCB));
ready_calculate->next =NULL;
ready_io->next =NULL;
death->next=NULL;
create=CreateThread(NULL,0,pro_create,NULL,0,NULL);
execute=CreateThread(NULL,0,pro_execute,NULL,0,NULL);
io=CreateThread(NULL,0,pro_io,NULL,0,NULL);
exit=CreateThread(NULL,0,pro_exit,NULL,0,NULL);
CloseHandle(create);
CloseHandle(execute);
CloseHandle(io);
CloseHandle(exit);
_getch();
}
/****************读入进程****************/
//void open(PCB *&ready)
DWORD WINAPI pro_create(LPVOID lpParameter)
{
int i;
srand((int)time(0));
PCB *r,*p;
ifstream infile;
infile.open("pcbdata.txt",ios::in );
if(!infile)
{
WaitForSingleObject(hMutex,INFINITE);
cout<<"没有找到PCB数据文件!/n";
ReleaseMutex(hMutex);
}
else
{
for(i=0;i<SIZE;i++)
{ //初始化
p=(PCB *)malloc(sizeof(PCB));
/*srand((int)time(0));*/
infile>>p->name ;
p->priority=1+(int)(7*rand()/(RAND_MAX+1.0));
p->progress=0;
p->progressFinished=0;
p->status ='r';
p->next=NULL;
p->all_q_next=NULL;
p->time =0;
r=ready_calculate;
while(r->next !=NULL && r->next->priority >=p->priority )
r=r->next;
p->next =r->next ;
r->next =p;
/*Sleep(1000);*/
}
infile.close ();
WaitForSingleObject(hMutex,INFINITE);
r=ready_calculate/*->next */;
do
{
r=r->next;
cout<<r->name<<" "<<r->priority<<" "<<r->progress<<" "<<r->progressFinished<<" "<<r->status <<" "<<r->next<<" "<<r->all_q_next<<" "<<r->time<<"/n";
}while(r->next!=NULL); //试验有没有正确读取文件
ReleaseMutex(hMutex);
}
return 0;
}
/*************运行进程****************/
DWORD WINAPI pro_execute(LPVOID lpParameter)
{
while(IOIsAlive)
{
while(ready_calculate->next !=NULL)
{
PCB *r,*p;
//所有任务等待时间先加1
p=ready_calculate;
while(p->next !=NULL)
{
p=p->next ;
p->time ++;
}
//运行的作业p 等待时间置0
p=ready_calculate->next ;
p->time =0;
//p拿出来,队列却还需继承下去
ready_calculate->next=p->next ;
switch(p->progressFinished )
{
case 0:
p->progressFinished=1;
p->progress+=10;
/* WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第一阶段的计算工作,已计算"<<p->progress<<"秒../n";
/*ReleaseMutex(hMutex);*/
//找位置插入ready_calculate
r=ready_calculate;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time )) //总得考虑等待时间吧..
r=r->next;
p->next =r->next ;
r->next =p;
break;
case 1:
p->progress+=10;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第一阶段的计算工作,已计算"<<p->progress<<"秒../n";
/*ReleaseMutex(hMutex);*/
if(p->progress==100) //计算完成,将其插入IO队列
{
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<p->name <<"第一阶段的计算工作已完成,转入第二阶段的输入操作.../n";
/*ReleaseMutex(hMutex);*/
p->progress=0;
p->progressFinished=2;
r=ready_io;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
}
else //计算尚未完成,再插入计算队列
{
r=ready_calculate;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time )) //总得考虑等待时间吧..
r=r->next;
p->next =r->next ;
r->next =p;
}
break;
case 2:
case 3:
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"计算线程有问题!!../n";
/*ReleaseMutex(hMutex);*/
break;
case 4:
p->progress+=10;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第四阶段的计算工作,已计算"<<p->progress<<"秒../n";
/*ReleaseMutex(hMutex);*/
if(p->progress==200) //计算完成,将其插入IO队列
{
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<p->name <<"第四阶段的计算工作已完成,转入第五阶段的输入操作.../n";
/*ReleaseMutex(hMutex);*/
p->progress=0;
p->progressFinished=5;
r=ready_io;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
//10个作业要是都做完,那就不要再计算了
finish4++;
if(finish4==10)
CalculateIsAlive=0;
}
else //计算尚未完成,再插入计算队列
{
r=ready_calculate;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time )) //总得考虑等待时间吧..
r=r->next;
p->next =r->next ;
r->next =p;
}
break;
case 5:
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"计算线程有问题!!../n";
/*ReleaseMutex(hMutex);*/
break;
}
Sleep(1); //睡上100微秒,够米?
}
}
return 0;
}
/***************IO操作*****************/
DWORD WINAPI pro_io(LPVOID lpParameter)
{
while(CalculateIsAlive)
{
while(ready_io->next !=NULL)
{
PCB *r,*p;
//所有任务等待时间先加1
p=ready_io;
while(p->next !=NULL)
{
p=p->next ;
p->time ++;
}
//运行的作业p 等待时间置0
p=ready_io->next ;
p->time =0;
ready_io->next =p->next ;
switch(p->progressFinished )
{
case 0:
case 1:
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"IO貌似出问题啦!!../n";
/*ReleaseMutex(hMutex);*/
break;
case 2:
p->progress+=10;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第二阶段的输入工作,已输入"<<p->progress<<"秒../n"; //昏哦,怎么看上去感觉输入也是间断的额
/*ReleaseMutex(hMutex);*/
if(p->progress==50)
{
p->progress=0;
p->progressFinished=3;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<p->name <<"第二阶段的计算工作已完成,转入第三阶段的输入操作.../n";
/*ReleaseMutex(hMutex);*/
}
r=ready_io;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
break;
case 3:
p->progress+=10;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第三阶段的输出工作,已输入"<<p->progress<<"秒../n";
/*ReleaseMutex(hMutex);*/
if(p->progress==30)
{
p->progress=0;
p->progressFinished=4;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<p->name <<"第三阶段的计算工作已完成,转入第四阶段的计算操作.../n";
/*ReleaseMutex(hMutex);*/
r=ready_calculate;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
}
else
{
r=ready_io;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
}
break;
case 4:
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"IO貌似出问题啦!!../n";
/*ReleaseMutex(hMutex);*/
break;
case 5:
p->progress+=10;
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"正在进行"<<p->name <<"第五阶段的输入工作,已输入"<<p->progress<<"秒../n";
/*ReleaseMutex(hMutex);*/
if(p->progress==20)
{
//恭喜进入死亡队列,死亡队列就不管你优先级啦——死都死了
/*WaitForSingleObject(hMutex,INFINITE);*/
cout<<"作业"<<p->name <<"已完成../n";
/*ReleaseMutex(hMutex);*/
p->next =death->next ;
death->next =p;
//10个作业要是都做完,那就不要再IO了
finish5++;
if(finish5==10)
IOIsAlive=0;
}
else
{
r=ready_io;
while(r->next !=NULL && (r->next->priority +r->next->time ) >=(p->priority +p->time ))
r=r->next;
p->next =r->next ;
r->next =p;
}
break;
}
Sleep(1); //睡上10微秒,够米?
}
/*ReleaseMutex(hMutex);*/
}
return 0;
}
/***************进程撤销**************/
DWORD WINAPI pro_exit(LPVOID lpParameter)
{
while(IOIsAlive||death->next !=NULL)
{
death->next=NULL;
}
cout<<"全做完了,好轻松..";
return 0;
}
这篇文章算是抛砖引玉吧,网上强人很多,对这个程序可能有不同的看法。我们老师也可能布置这种作业,但是希望大家不要照抄,真正理解程序究竟是如何运行的,才是最重要的。