院 系:计 算 机 学 院
实验课程:操作系统教程
实验项目:进程调度的设计与实现
指导老师:冯刚
开课时间:2012 ~ 2013 年度第 2 学期
专 业:网络工程
班 级:11 级 6 班
学 生:黄兴静
学 号:20112100185
1
目录
一、 实验的目的………………………………………………1
二、 实验的内容(任务)及要求……………………………1
三、 实验设备及环境…………………………………………1
四、 实验的原理………………………………………………1
五、 关键算法的实现流程图…………………………………2
六、 实验的设计思想及相关代码……………………………3
七、 实验的图形用户界面 GUI 设计…………………………8
八、 心得体会…………………………………………………8
2
一、实验的目的
1、 综合应用下列知识点设计并实现操作系统的进程调度:邻接表,布尔数组,
非阻塞输入,图形用户界面 GUI ,进程控制块,进程状态转换,多级反馈队列
进程调度算法。
2、 加深理解操作系统进程调度的过程。
3、 加深理解多级反馈队列进程调度算法。
二、实验的内容(任务)及要求
1、设计一个虚拟处理机,编程序演示多级反馈队列调度算法的具体实现过程
2、用一种熟悉的语言,如 C、PASCAL 或 C++等,编制程序。在这次实验中,关
键代码(即多级反馈队列调度算法的代码)采用 C++,而界面设计采用 MFC 界面
设计。
三、实验设备及环境
PC(即电脑), Microsoft Visual C++ 6.0(编程软件)
四、实验的原理
多级反馈队列调度算法:
1、设置多个就绪队列,并给队列赋予不同的优先级数,第一个最高,依次递减。
2、赋予各个队列中进程执行时间片的大小,优先级越高的队列,时间片越小。
但在本实验中,各个队列中进程执行时间片的大小都为 1。
3、当一个新进程进入内存后,首先将其放入第一个队列末尾,按 FCFS 原则排
队等待调度;当轮到该进程执行时,如能在该时间片内完成,便可准备撤离系
统;如果在一个该时间片结束时尚未完成,将其转入第二队列末尾,再同样按
FCFS 原则排队等待调度执行;如果它在第二队列中运行一个该时间片仍未完
成,再依次将它转入第三队列。如此下去,当一个进程从一个对列移至第 n 个
队列后,便在第 n 个队列中采用时间片轮转执行完(最后一个队列的进程采用
时间片轮转执行完)
但在本实验中,一个新进程进入内存后,是将其放入某个就绪队列的末尾。当
轮到该进程执行时,如能在该时间片内完成,便可准备撤离系统;如果在一个
该时间片结束时尚未完成,将其转入优先级减半的队列末尾,如果它在第二队
列中运行一个该时间片仍未完成,再依次将它转入优先级减半的队列。如此下
去,当一个进程从一个对列移至第 n 个队列后,便在第 n 个队列中采用时间片
轮转执行完(最后一个队列的进程采用时间片轮转执行完)
4、仅当时间片空闲时,才调度第二个队列中的进程。(1~i-1)空闲时,才调度 i,
如果处理机正在第 i 队列中运行,在低优先级的队列中的进程在运行时,又有新
到达的作业,那么在运行完这个时间片后,CPU 马上分配给新到达的作业,即
新进程抢占处理机(抢占式),将正在运行的进程放入原来队列的下一个队列的
队尾,将处理机分给新进程。
3
但在本实验中,实验要求并没有要求我们实现进程抢占式
五、关键算法的实现流程图
开始
随机生成数个进程
调度进程
执行进程 i
是否按下
crtl+f?
Y
插入新进程
N
进程 i 移到就绪队列
CPU 调新进程
继续执行进程 i
优先级减半
生命周期减 1
生命周期为
0?
Y
进程 i 完成
撤销 PCB
N
进程 i 变就绪状态
插入就绪队列
4
六、实验的设计思想及相关代码
Ⅰ每一个进程都有一个对应的进程控制块,即 PCB,其里面函数变量有进程标识
符 pid、进程的状态标识 status、进程优先 priority 和表示进程生命周期的数
据项 life (在实际系统中不包括该项)。
struct PCB
{
}
int pid;
int status;
int priority;
int life;
//进程标识符
//进程的状态标识,0 表示就绪,1 表示运行
//进程优先级
//进程生命周期
Ⅱ进程状态 status 的取值为“就绪 ready”或“运行 run ”,刚创建时,状
态为“ready”,用整数 0 表示。被进程调度程序选中后变为“run”,用整数 1
表示。
Ⅲ进程优先级 priority 是 0 到 49 范围内的一个随机整数。
srand(unsigned(time(0)));
priority=rand()%50+1;
//在本次实验的进程优先级中,我用 1 到 50 范围内的一个随机数,是为了后面
的进程执行次序的代码作铺垫。
Ⅳ进程生命周期 life 是 1 到 5 范围内的一个随机整数。
srand(unsigned(time(0)));
priority=rand()%5+1;
Ⅰ到Ⅳ可得到进程创建的代码
//添加进程
void 头文件的名字::OnButton1()
{
//stop=true;
// TODO: Add your control notification handler code here
sum++;//进程数+1;
srand(unsigned(time(0)));
p[sum].pid=sum;//生成相同 id,有 BUG
p[sum].life=rand()%5+1;
p[sum].priority=rand()%50+1;
p[sum].status=0;//准备状态;
q[p[sum].priority].push(p[sum]);
5
show();
//stop=false;
UpdateData(TRUE);
}
Ⅴ初始化时,创建一个邻接表,包含 50 个就绪队列,各就绪队列的进程优先级
priority 分别是 0 到 49。 注意:本次实验我用的是 1 到 50
在函数头文件中加函数变量:
queue
q[51];
queueq1[51];
Ⅵ为了模拟用户动态提交任务的过程,要求动态创建进程。进入进程调度
循环后,每次按 ctrl+f 即动态创建一个进程,然后将该 PCB 插入就绪队
列中。按 ctrl+q 退出进程调度循环。
1. 首先在头文件中加上(红色加粗部分为增加项,位置不能随意):
afx_msg LRESULT OnHotKey(WPARAM wParam,LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
2. 关联消息及函数(红色加粗部分为增加项,位置不能随意):
BEGIN_MESSAGE_MAP(头文件的名字, CDialog)
//{{AFX_MSG_MAP(头文件的名字)
ON_MESSAGE(WM_HOTKEY,OnHotKey) //消息和函数发生关联
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
3. 定义消息号在头文件的 CPP 文件的:: OnInitDialog()函数中加上(位置不限)
RegisterHotKey(m_hWnd, 1001, MOD_CONTROL,'F');,
RegisterHotKey(m_hWnd, 1002, MOD_CONTROL,'5');
RegisterHotKey(m_hWnd, 1003, MOD_CONTROL,'Q');
4. 定义响应函数
//自定义快捷键
LRESULT 头文件的名字::OnHotKey(WPARAM wParam,LPARAM lParam)
{
// TODO: Add your code here
if(wParam==1001)
{
OnButton1();
}
else if(wParam==1002)
6
{
OnButton2();
}
else if(wParam==1003)
{
OnButton3();
}
return 0;
}
}
void 头文件的名字::OnButton3()
{
// TODO: Add your control notification handler code here
exit(0);
Ⅶ在进程调度循环中,每次选择优先级最大的就绪进程来执行。将其状态从就
绪变为运行,通过延时一段时间来模拟该进程执行一个时间片的过程,然后优
先级减半,生命周期减一。
void 头文件的名字::OnButton2()
{
// TODO: Add your control notification handler code here
for(int i=50;i>=1;i--)
{
bool flag=false;
CString str="";
while(!q[i].empty())
{
flag=true;
PCB temp=q[i].front();
str=str+"进程 ID:";
CString s;
s.Format(_T("%d"),temp.pid);
str=str+s+" 进程生命时间:";
s.Format(_T("%d"),temp.life);
str=str+s+" ";
temp.life--;
temp.priority=temp.priority/2;
if(temp.life>0)
{
if(temp.priority>0)
7
else
q[temp.priority].push(temp);
q[1].push(temp);//重新加入队尾
sum--;
q[0].push(temp);
}
q[i].pop();
//延迟有问题
SetDlgItemText(IDC_EDIT51,str);
show();
UpdateData(TRUE);
break;
}
else
{
}
if(flag)
{
}
}
}
Ⅷ设计图形用户界面 GUI ,在窗口中显示该进程和其他所有进程的 PCB 内容。
如果将该运行进程的生命周期不为 0 ,则重新把它变为就绪状态,插入就绪队
列中;否则该进程执行完成,撤消其 PCB 。以上为一次进程调度循环。
1、 首先在头文件中的 public:加上:输出函数 void show();
例如:
{
// Construction
public:
头文件的名字(CWnd* pParent = NULL);
void show();
// standard constructor
}
2、 在头文件.cpp 文件定义输出函数 void show();的响应函数
void 头文件的名字::show()
{
CString Str="";
CString str="";
int id=IDC_EDIT1;
for(int i=1;i<=50;i++)
8