进程管理实验报告
一、进程与线程
1.实验目的:
1.通过本实验学习Linux中创建进程的方法。
2.学习系统调用fork的使用方法。
3.学习系统调用exec族调用的使用方法。
2.实验准备
1. 进程的创建
创建一个进程的系统调用很简单,只要调用fork函数就可以了。
#include<unistd.h>
pid_t fork();
当一个进程调用了fork以后,系统会创建一个子进程,这个子进程和父进程是不同的地方只有它的进程ID和父进程ID,其他的都一样,就像父进程克隆(clone)自己一样,当然创建两个一模一样的进程是没有意义的,为了区分父进程和子进程,我们必须跟踪fork调用返回值。当fork调用失败的时候(内存不足或者是用户的最大进程数已到)fork返回—1,否则fork的返回值有重要的作用。对于父进程fork返回子进程ID,而对于fork子进程返回0,我们就是根据这个返回值来区分父子进程的。
2.关于fork的说明
使用该函数时,该函数被调用一次,但返回两次,两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。
将子进程ID返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数可以是一个子进程获得其所有子进程的进程ID。
而fork函数使子进程得到的返回值是0的理由是:一个子进程只会有一个父进程,所以子进程总是可以调用函数getpid获得其父进程的进程ID。
3.系统调用exec族调用的说明
父进程创建子进程后,子进程一般要执行不同的程序。为了调用系统程序,我们可以使用系统调用exec族调用。Exec族调用有以下五个函数:
int execl(const char *path,const char*arg,…);
int execlp(const char *file, const char*arg,…);
int execle(const char *path,const char*arg,…);
int execv(const char *path,const char*argv[]);
int execvp(const char *file, const char*argv[]);
exec族调用可以执行给定程序。关于exec族调用的详细解说可以参考系统手册。
3.实验内容及步骤
编程实现使用fork函数创建子进程,以及在子进程中调用exec族调用的程序。
1、进入Linux操作系统中的终端显示如下:
在系统shell提示符下输入vi及文件名后,进就入vi编辑画面。如果系统内还不存在该文件,就意味着要穿件文件。如果系统内存在该文件,就意味着要编辑该文件。下面就是用vi编辑器创建文件的实例。
{root@localhost }#vi filename
此后文件的编译都使用同样的方法,不再赘述。
2、目前,Linux系统下的应用程序多由C语言编写,最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSIC标准的编译系统,能够编译用C、C++等语言编写的程序。
在使用GCC之前,下面的这个例子能够帮助用户迅速理解GCC的工作原理,并将其立即运用到实际的项目开发中去。
首先用vi编译器按照下面的内容创建一个名为hello.c的文件。
#filename:hello.c
#include
Int main(void)
{
printf(“Hello World,Linux programming!”);
return 0;
}
然后执行下面的命令编译和运行这段程序:
#gcc hello.c –o hello
#./hello
Hello world,Linux programming!
此后的程序均按照这种方法运行,下文中将不再赘述。
4.参考程序
1、使用fork函数创建子进程的程序 fork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[]){
pid_t childpid;
if((childpid=fork())==0){
printf("I am the child process,my ID is %ld\n",(long)getpid());
}
else if(childpid>0){
printf("I am the parent process,my ID is %ld\n",(long)getpid());
}
}
2、创建子进程后调用系统调用execlp的程序 execlp.c
#include <stdio.h>
#include <unistd.h>
int main(int argc,char * argv[])
{
pid_t pid;
pid=fork();
if(pid<0){
fprintf(stderr,"Fork Failed");
exit(-1);
}
else if(pid==0){
execlp("/bin/date","date",NULL);
}//执行另外一个程序
else{
wait(NULL);
printf("child complete\n");
exit(0);
}
}
5.实验结果
1.fork.c
2.execlp.c
电子信息工程学系实验报告 ——适用于计算机课程
课程名称: 操作系统
实验项目名称:银行家算法 实验时间:2014.4.4-4.20
班级:计算机122 姓名:李鹏辉 学号:201210704214
实 验 目 的:
1.理解死锁避免相关内容;
2.掌握银行家算法主要流程;
3.掌握安全性检查流程。
操作系统中的死锁避免部分的理论进行实验。要求实验者设计一个程序,该程序可对每一次资源申请采用银行家算法进行分配。
实 验 环 境:
PC机、windows2000 操作系统、Turbo C 2.0 / VC++6.0
实 验 内 容 及 过 程:
设计一个有N个进程并行的进程调度程序。
进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。具体描述如下:
每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。
分析:进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。
进程的运行时间以时间片为单位进行计算。
每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。 就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。
如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后按照优先数的大小把它插入就绪队列等待CPU。
每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。 重复以上过程,直到所要进程都完成为止。
调度算法的参考流程图如下:
死锁避免定义:在系统运行过程中,对进程发出的每一个资源申请进行动态检查,并根据检查结果决定是否分配资源:若分配后系统可能发生死锁,则不予分配,否则予以分配。
由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
1 系统安全状态
1)安全状态
所谓系统是安全的,是指系统中的所有进程能够按照某一种次序分配资源,并且依次地运行完毕,这种进程序列{ P1 ,P2 …Pn}就是安全序列。如果存在这样一个安全序列,则系统是安全的。
并非所有的不安全状态都会转为死锁状态,但当系统进入不安全状态后,便有可能进入死锁状态;反之,只要系统处于安全状态,系统便可避免进入死锁状态。所以避免死锁的实质:系统在进行资源分配时,如何使系统不进入不安全状态。
2)安全状态之例
假设系统有三个进程,共有12台磁带机。各进程的最大需求和T0时刻已分配情况如下表:
答:T0时刻是安全的,因为存在安全序列:P2 ?P1? P3
不安全序列:P1?…
P3?…
P2?P3?P1
3)由安全状态向不安全状态的转换
如果不按照安全序列分配资源,则系统可能会由安全状态进入不安全状态。例如,在T0时刻以后,P3又请求1台磁带机,若此时系统把剩余3台中的1台分配给P3,则系统便进入不安全状态。 因为,此时也无法再找到一个安全序列, 例如,把其余的2台分配给P2,这样,在P2完成后只能释放出4台,既不能满足P1尚需5台的要求,也不能满足P3尚需6台的要求,致使它们都无法推进到完成,彼此都在等待对方释放资源,即陷入僵局,结果导致死锁。
2 利用银行家算法避免死锁
1)银行家算法中的数据结构
① 可利用资源向量Available。
这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。如果Available[j]=K,则表示系统中现有Rj类资源K个。
② 最大需求矩阵Max。
最大需求矩阵Max。这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。
③ 分配矩阵Allocation
这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的数目为K。
④ 需求矩阵Need
这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。
Need[i,j]=Max[i,j]-Allocation[i,j]
2)银行家算法
设Requesti是进程Pi的请求向量,如果Requesti[j]=K,表示进程Pi需要K个Rj类型的资源。当Pi
发出资源请求后,系统按下述步骤进行检查:
(1) 如果Requesti[j]≤Need[i,j],便转向步骤2;否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2) 如果Requesti[j]≤Available[j],便转向步骤(3);否则, 表示尚无足够资源,Pi须等待。
(3) 系统试探着把资源分配给进程Pi
,并修改下面数据结构中的数值:
Available[j]∶=Available[j]-Requesti[j];
Allocation[i,j]∶=Allocation[i,j]+Requesti[j];
Need[i,j]∶=Need[i,j]-Requesti[j];
(4) 系统执行安全性算法,检查此次资源分配后,系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则, 将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。
行家算法的参考流程图如下:
3)安全性算法
(1) 设置两个向量: ① 工作向量Work: 它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素,在执行安全算法开始时,Work∶=Available;
② Finish: 它表示系统是否有足够的资源分配给进程,使之运行完成。开始时先做Finish[i]∶=false; 当有足够资源分配给进程时, 再令Finish[i]∶=true。
(2) 从进程集合中找到一个能满足下述条件的进程:
① Finish[i]=false;
② Need[i,j]≤Work[j]; 若找到, 执行步骤(3), 否则,执行步骤(4)。 (3) 当进程Pi
获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
Work[j]∶=Work[i]+Allocation[i,j];
true; Finish[i]∶= go to step (2);
(4) 如果所有进程的Finish[i]=true都满足, 则表示系统处于安全状态;否则,系统处于不安全状态。
安全性算法的参考流程图如下:
实 验 结 果 及 分 析:
创建基本信息
进程1申请资源成功
申请资源大于总资源,失败
实 验 心 得:
本次实验,我们看到银行家算法确实能保证系统时时刻刻都处于安全状态,但它要不断检测每个进程对各类资源的占用和申请情况,需花费较多的时间。
附 录:
#include "string.h"
#include "iostream.h"
#define M 5
#define N 3
#define FALSE 0
#define TRUE 1
int MAX[M][N]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};
int AVAILABLE[N]={10,5,7};
int ALLOCATION[M][N]={{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}};
int NEED[M][N]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};
int Request[N]={0,0,0};
void main()
{
int i=0,j=0;
char flag='Y';
void showdata();
void changdata(int);
void rstordata(int);
int chkerr(int);
showdata();
while(flag=='Y'||flag=='y')
{
i=-1;
while(i<0||i>=M)
{
cout<<" 请输入需申请资源的进程号(从0到"<<M-1<<",否则重输入!):";
cin>>i;
if(i<0||i>=M) cout<<" 输入的进程号不存在,重新输入!"<<endl;
}
cout<<" 请输入进程"<<i<<"申请的资源数"<<endl;
for (j=0;j<N;j++)
{
cout<<" 资源"<<j<<": ";
cin>>Request[j];
if(Request[j]>NEED[i][j])
{
cout<<" 进程"<<i<<"申请的资源数大于进程"<<i<<"还需要"<<j<<"类资源的资源量!"; cout<<"申请不合理,出错!请重新选择!"<<endl<<endl;
flag='N';
break;
}
else
{
if(Request[j]>AVAILABLE[j])
{
cout<<" 进程"<<i<<"申请的资源数大于系统可用"<<j<<"类资源的资源量!"; cout<<"申请不合理,出错!请重新选择!"<<endl<<endl;
flag='N';
break;
}
}
}
if(flag=='Y'||flag=='y')
{
changdata(i);
if(chkerr(i))
{
rstordata(i);
showdata();
}
else
showdata();
}
else
showdata();
cout<<endl;
cout<<" 是否继续银行家算法演示,按'Y'或'y'键继续,按'N'或'n'键退出演示:"; cin>>flag;
}
}
void showdata()
{
int i,j;
cout<<" 系统可用的资源数为:"<<endl<<endl;
cout<<" ";
for(j=0;j<N;j++) cout<<" 资源"<<j<<": "<<AVAILABLE[j];
cout<<endl;
cout<<endl;
cout<<" 各进程还需要的资源量:"<<endl<<endl;
for(i=0;i<M;i++)
{
cout<<"进程"<<i<<":";
for(j=0;j<N;j++) cout<<" 资源"<<j<<", "<<NEED[i][j];
cout<<endl;
}
cout<<endl;
cout<<" 各进程已经得到的资源量:"<<endl<<endl;
for(i=0;i<M;i++)
{
cout<<"进程"<<i<<":";
for(j=0;j<N;j++) cout<<" 资源"<<j<<": "<<ALLOCATION[i][j];
cout<<endl;
}
cout<<endl;
};
void changdata(int k)
{
int j;
for(j=0;j<N;j++)
{
AVAILABLE[j]=AVAILABLE[j]-Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]+Request[j]; NEED[k][j]=NEED[k][j]-Request[j];
}
};
void rstordata(int k)
{
int j;
for(j=0;j<N;j++)
{
AVAILABLE[j]=AVAILABLE[j]+Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]-Request[j]; NEED[k][j]=NEED[k][j]+Request[j];
}
};
int chkerr(int s)
{
int WORK,FINISH[M],temp[M];
int i,j,k=0;
for(i=0;i<M;i++) FINISH[i]=FALSE;
for(j=0;j<N;j++)
{
WORK=AVAILABLE[j];
i=s;
while(i<M)
{
if(FINISH[i]==FALSE&&NEED[i][j]<=WORK) {
WORK=WORK+ALLOCATION[i][j];
FINISH[i]=TRUE;
temp[k]=i;
k++;
i=0;
}
else
{
i++;
}
}
for(i=0;i<M;i++)
if(FINISH[i]==FALSE)
{
cout<<endl;
cout<<" 系统不安全!!!本次资源申请不成功!!!"<<endl; cout<<endl;
return 1;
}
}
cout<<endl;
cout<<" 经安全性检查,系统安全,本次分配成功。"<<endl; cout<<endl;
cout<<" 本次安全序列:";
for(i=0;i<M;i++) cout<<"进程"<<temp[i]<<"->";
cout<<endl<<endl;
return 0;
};
备注:以上各项空白处若填写不够,可自行扩展
实验一进程管理一目的进程调度是处理机管理的核心内容本实验要求编写和调试一个简单的进程调度程序通过本实验加深理解有关进程控制块进程队…
一、实验目的本实验要求学生编写和调试一个系统动态分配资源的简单模拟程序,观察死锁产生的条件,并采用适当的算法,有效地防止和避免死锁…
实验一进程管理1目的和要求通过实验理解进程的概念进程的组成PCB结构进程的并发执行和操作系统进行进程管理的相关原语主要是进程的创建…
操作系统实验一进程管理实验班级20xx211311学号姓名schnee目录1234实验目的3实验预备内容3环境说明3实验内容441…
沈阳理工大学课程设计任务书1沈阳理工大学目录1课程设计目的32课程设计要求33相关知识34需求分析45概要设计56详细设计67测试…
实验二进程管理一进程的创建实验思考题1系统是怎样创建进程的解linux系统创建进程都是用fork系统调用创建子进程2当首次调用新创…
实验二进程管理二进程的控制实验思考题1可执行文件加载时进行了哪些处理解可执行文件加载时首先是创建一个新进程的fork系统调用然后用…
XXXX大学20xx年20xx年第2学期院系计算机信息工程学院专业信息管理与信息系统课程名称操作系统原理及应用班级姓名学号指导教师…
实验一进程管理一目的进程调度是处理机管理的核心内容本实验要求编写和调试一个简单的进程调度程序通过本实验加深理解有关进程控制块进程队…
1一设计理论描述通过掌握动态优先数调度算法以及采用时间片轮转调度算法的基本原理按动态优先数法每进程调度完一个单位的时间就要修改一下…