1.1理解进程的概念,明确进程和程序的区别。
1.2理解并发执行的实质。
1.3掌握进程的创建、睡眠、撤销等进程控制方法。
通常,一个进程必须具有就绪、执行和阻塞3种基本状态。
(1)就绪状态
当进程已分配到除处理器(CPU)以外的所有必要资源后,只要再获得处理器就可以立即执行,这时进程的状态称为就绪状态。在一个系统里,可以有多个进程同时处于就绪状态通常把这些就绪进程排成一个或多个队列,称为就绪队列。
(2)执行状态
处于就绪状态的进程一且获得了处理器,就可以运行,进程状态也就处于执行状态。在单处理器系统中,只能有一个进程处于执行状态,在多处理器系统中,则可能有多个进程处于执行状态。
(3)阻塞状态
正在执行的进程因为发生某些事件(如请求输入输出、中请额外空间等)而暂停运行,这种受阻暂停的状态称为阻塞状态,也可以称为等待状态。通常将处于阻塞状态的进程排成一个队列,称为阻塞队列。在有些系统中,也会按阻塞原因的不同将处于阻塞状态的进程排成多个队列。
除了进程的3种基本状态外,在很多系统为了更好地描述进程的状态变化,又增加了两种状态。
(4)新状态
当一个新进程刚刚建立,还未将其放入就绪队列的状态,称为新状态。例如一个人刚开始接受教育,此时就可以称其处于于新状态。
(5)终止状态
当一个进程己经正常结東或异常结東,操作作系统已将其从系统队列中移出,但尚未撤消,这时称为终止状态。
1.进程控制块的作用
进程控制块是构成进程实体的重要组成部分,是操作系统中最重要的记录型数据,在进程控制块PCB中记录了操作系统所需要的、用于描述进程情况及控制进程运行所需要的全基本单位,一个能够并发执行的进程。换句话说,在进程的整个生命周期中,操作系统都要通过进程的PCB来对并发执行的进程进行管理和控制,进程控制块是系统对进程控制采用的数据结构,系统是根据进程的PCB而感知进程是否存在。所以,进程控制块是进程存在的唯一标志。当系统创建一个新进程时,就要为它建立一个PCB:进程结束时,系统又回收其PCB,进程也随之消亡。
2.进程控制块的内容
进程控制块主要包括下述四个方面的信息。
1)进程标识信息
进程标识符用于标识一个进程,通常有外部标识符和内部标识符两种。
(1)外部标识符
由创建者命名,通常是由字母、数字所组成的一个字符串,在用户(进程)访问该进程时使用。外部标识符都便于记忆,如计算进程、打印进程、发送进程、接接收进程等。
(2)内部标识符
是为方便系统使用而设置的,操作系统为每一个进程赋予唯一的一个整数,作为内部标识符。它通常就是一个进程的序号。
2)说明信息(进程调度信息)
说明信息是有关进程状态等一些与进程调度有关的信息,包括:
(1)进程状态
指明进程当前的状态,作为进程调度和对换时的依据。
(2)进程优先级
用于描述进程使用处理器的优先级别,通常是一个整数,优先权高的进程将可以优先获得处理器。
(3)进程调度所需的其他信息
其内容与所采用的进程调度算法有关,如进程等待时间、进程己执行时间等。
(4)阻塞事件
指进程由执行行状态转变为阻塞所等待发生的事件,即阻塞原因。
3)现场信息(处理器状态信息)
现场信息是用于保留进程存放在处理器中的各种信息,主要由处理器中各种寄存器的内容组成。尤其是当执行中的进程暂停时,这些寄存器内的信息将被保存在PCB里,当该中再次获得执行时,能从上次停止的地方继续执行。
(1)通用寄存器:其中的内容可以被用户程序访问,用于暂存信息。
(2)指令计数器:存放要访问的下一条指令的地址。
(3)程序状态字:保存当前处理器状态的信息,如执行方式、中断屏蔽标志等。
(4)用户栈指针:每个用户进程都有一个或若干个与之联系的关联栈,用于存放过程和系统调用参数及调用地址,栈指针指向堆栈的栈顶。
4)管理信息(进程控制信息)
(1)程序和数据的地址:它是指该进程的程序和数据所在的主存和外存地址再次执行时,能够找到程勋和数据。
(2)进程同步和通信机制:它是指实现进程同步和进程通信时所采用的的机制、指针、信号量等。
(3)资源清单:该清单存放有(除了CPU以外)进程所需的全部资源和已经分配到的资源。
(4)链接指针:它将指向该进程所在队列的下一个进程PCB的首地址。
3.进程控制块的组织方式
在一个系统中,通常拥有数十个、数百个乃至数千个PCB,为了能对他们有效的管理,就必须通过适当的方式将它们组织起来,日前常用的组织方式有链接方式和索引方式两种。
(1)链接方式
把具有相同状态的PCB,用链接指针链接成队列,如就绪队列、阻塞队列和空闲队列等。就绪队列中的PCB将按照相应的进程调度算法进行排序。而阻塞队列也可以根据阻塞原因的不同,将处于阻塞状态的进程的PCB,排成等待I/O队列、等待主存队列等多个队列。此外,系统主存的PCB区中空闲的空间将排成空闲队列,以方便PCB的分配和回收。
(2)索引方式
系统根据各个进程的状态,建立不同索引表,例如就绪索引表、阻塞索引表等。并把各个索引表在主存的首地址记录在主存中的专用单元里,也可以称为表指针。在每个索引表的表目中,记录着具有相同状态的各个PCB在表中的地址。
4.进程控制原语
系统根据各个进程的状态,建立不同索引表,例如就绪索引表、阻塞索引表等。并把各个索引表在主存的首地址记录在主存中的专用单元里,也可以称为表指针。在每个索引表的表目中,记录着具有相同状态的各个PCB在表中的地址。
(1)创建原语。用于为一个进程分配工作区和PCB,并初始化PCB,进程处于就绪态。
(2)撤销原语。用于一个进程完成后,收回它的工作区和PCB。
(3)阻塞原语。用于进程在运行过程中发生等待时间时,将进程改为阻塞态。
(4)唤醒原语。用于当进程等待的事件发生时,将进程改为就绪态。
1.进程的创建
一旦操作系统发现了要求创建进程的事件后,便调用进程创建原按下列步骤创建一个新进程。
①为新进程分配惟一的进程标识符,并从PCB队列中申请一个空闲PCB。
②为新进程的程序和数据,以及用户栽分配相应的主存空间及其他必要分配资源。
③初始化PCB中的相应信息,如标识信息、处理器倌息、进程控制倌息等
④如果就绪队列可以接纳新进程,便将新进程加入到就绪队列中。
2.进程的撤销
一旦操作系统发现了要求终止进程的事件后,便调用进程终止原语按下列步骤终止指定的进程。
①根据被终止进程的标识符,从PCB集合中检索该进程的PCB,读出进程状态。
②若该进程处于执行状态,则立即终止该进程的执行。
③若该进程有子孙进程,还要将其子孙进程终止。
④将该进程所占用的资源回收,归还给其父进程或操作系统。
⑤将被终止进程的PCB从所在队列中移出,并撇销该进程的PCB。
1.进程的阻塞
一旦操作系统发现了要求阻塞进程的事件后,便调用进程阻塞原语,按下列步骤阻塞指定的进程。
①立即停止执行该进程。
②修改进程控制块中的相关信息。把进程控制块中的运行状态由“执行”状态改为“阻塞”状态,并填入等待的原因,以及进程的各种状态信息。
③把进程控制块插入到阻塞队列。根据阻塞队列的组织方式插入阻塞队列中。
④待调度程序重新调度,运行就绪队列中的其他进程。
2.进程的唤醒
一且操作系统发现了要求唤醒进程的事件后,便调用进程唤醒原语,按下列步骤唤醒指定的进程。
①从阻塞队列中找到该进程。
②修改该进程控制块的相关内容。把阻塞状态改为就绪状态,删除等待原因等。
③把进程控制块插入到就绪队列中。
按照就绪队列的组织方式,把被唤醒的进程的进程控制块插入到就绪队列中。
1.必须独立完成程序的调试和运行,记录运行结果并对结果进行分析;
2.分析程序所定义使用的数据结构;
3.分析程序的结构,并画出程序流程图;
4.撰写分析报告
2.数据类型定义:
struct type
{
int pid;
int youxian;
int daxiao;
int zhuangtai;//标识进程状态,0-不在内存,1-在内存,2-阻塞
char info[10];
};
struct type neicun[20];
int sum = 0;
int zuse = 0;
int pid = 0;
int flag = 0;
完整代码如下:
#include
#include
#include
struct type
{
int pid;
int youxian;
int daxiao;
int zhuangtai;//标识进程状态,0-不在内存,1-在内存,2-阻塞
char info[10];
};
struct type neicun[20];
int sum = 0;
int zuse = 0;
int pid = 0;
int flag = 0;
void create()
{
if(sum >= 20)
{
printf("\n内存已满,请先唤醒或杀死进程n");
}
else
{
int i;
for(i = 0; i < 20; i++)
{
if(neicun[i].zhuangtai == 0)
break;
}
printf("\n请输入新进程pid\n");
scanf("%d", &(neicun[i].pid));
for(int j = 0; j < i; j++)
{
if(neicun[j].pid == neicun[i].pid)
{
printf("\n该进程已存在n");
return;
}
}//定位,找到可以还未创建的进程
printf("\n请输入新进程优先级\n");
scanf("%d", &(neicun[i].youxian));
printf("\n请输入新进程大小\n");
scanf("%d", &(neicun[i].daxiao));
printf("\n请输入新进程内容\n");
scanf("%s", &(neicun[i].info));
//创建进程,使标记位为1
neicun[i].zhuangtai = 1;
sum++;
}
}
void run()
{
for(int i = 0; i < 20; i++)
{
if(neicun[i].zhuangtai == 1)
{
//输出运行进程的各个属性值
printf("\npid=%d\t",neicun[i].pid);
printf("youxian=%d\t",neicun[i].youxian);
printf("daxiao=%d\t",neicun[i].daxiao);
printf("zhuangtai=%d\t",neicun[i].zhuangtai);
printf("info=%s\t",neicun[i].info);
flag = 1;
}
}
if(!flag)
{
printf("\n当前没有运行进程\n");
}
}
void zusetai()
{
if(!sum)
{
printf("当前没有运行进程\n");
return;
}
printf("\n输入阻塞进程的PID值");
scanf("%d", &pid);
for(int i = 0; i < 20; i++)
{
//定位,找到所要唤醒的进程,根据其状态做相应处理
if(pid == neicun[i].pid)
{
if(neicun[i].zhuangtai == 1)
{
neicun[i].zhuangtai = 2;
zuse++;
printf("\n已经成功阻塞进程\n");
}
else
if(neicun[i].zhuangtai == 0)
{
printf("\n要阻塞的进程不存在\n");
}
else
{
printf("\n要阻塞的进程已被阻塞\n");
}
flag = 1;
break;
}
} //找不到,则说明进程不存在
if(flag == 0)
{
printf("\n要阻塞的进程不存在\n");
}
}
void kill()
{
if(!sum)
{
printf("当前没有运行进程\n");
return;
}
printf("\n输入杀死进程的工PID值");
scanf("%d", &pid);
for(int i = 0; i < 20; i++)
{
//定位,找到所要杀死的进程,根据其状态做相应处理
if(pid == neicun[i].pid)
{
if(neicun[i].zhuangtai == 1)
{
neicun[i].zhuangtai = 0;
sum--;
printf("\n已成功杀死进程\n");
}
else
if(neicun[i].zhuangtai == 0)
{
printf("\n:要杀死的进程不存在\n");
}
else
{
printf("\n要杀死的进程已被阻塞\n");
}
flag = 1;
break;
}
}//找不到,则说明进程不存在
if(!flag)
{
printf("\n要杀死的进程不存在\n");
}
}
void huanxing()
{
if(sum == 0)
{
printf("当前没有运行的进程\n");
return;
}
if(zuse == 0) /*guaqi = 0,表示没有挂起的进程*/
{
printf("\n当前没有唤醒的进程\n");
return;
}
printf("\n请输入要唤醒的进程的pid值:\n");
scanf("%d",&pid);
for(int i = 0; i < 20; i++)
{
if(pid == neicun[i].pid)
{
flag = false;
if(neicun[i].zhuangtai == 2)
{
neicun[i].zhuangtai = 1; /*将该进程的状态设为挂起*/
zuse--;
sum++;
printf("\n该进程已成功唤醒\n" );
}
else
if(neicun[i].zhuangtai == 0)
{
printf("\n要唤醒的进程不存在\n" );
}
else
{
printf("\n要唤醒的进程已经在内存中\n" );
}
flag = 1;
break;
}
}
if(!flag)
{
printf("\n要唤醒的进程不存在\n");
}
}
int main()
{
int n = 1;
int num;
//一开始所有进程都不在内存中
for(int i = 0;i < 20; i++)
{
neicun[i].zhuangtai = 0;
}
while(n)
{
printf("\n**********************************************");
printf("\n* 进程控制演示系统 *");
printf("\n**********************************************");
printf("\n 1.创建新的进程 2.查看运行进程");
printf("\n 3.阻塞某个进程 4.杀死运行进程");
printf("\n 5.唤醒某个进程 6.退出程序 ");
printf("\n**********************************************");
printf("\n请选择(1~6):");
scanf("%d", &num);
switch(num)
{
case 1:
create();
break;
case 2:
run();
break;
case 3:
zusetai();
break;
case 4:
kill();
break;
case 5:
huanxing();
break;
case 6:
exit(0);
default:
n = 0;
}
flag = 0;//恢复标记
}
}
3阻塞一个进程如下图所示:
5.杀死进程2如下图所示:
6:
要唤醒进程如下图所示: