进程的基本概念
进程的定义
1.进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位又称为任务(Task or Job)
1.程序的一次执行过程
2.是正在运行程序的抽象
3.将一个cpu变换成多个虚拟cpu
4.系统资源以进程为单位分配,如内存,文件,每个具有独立的地址空间
5.操作系统将cpu调度给需要的进程
进程控制块pcb
PCB:
1.进程描述符,进程属性
2.操作系统用于管理控制进程的一个专门数据结构
3.记录进程的各种属性,描述进程的动态变化过程
进程表
1.所有进程的pcb集合
PCB内容
1.进程描述信息
1.pid(进程标识符)
2.进程名
3.uid(用户标识符)
4.进程组关系
2.进程控制信息
1.当前状态
2.优先级
3.代码执行入口地址
4.程序磁盘地址
5.运行统计信息(执行时间,页面调度)
6.进程间同步和通信
7.进程的队列和指针
8.进程的消息队列指针
3.资源使用情况
1.虚拟地址空间的状况
2.打开文件列表
4.cpu现在信息
1.计算器值
2.执行该进程页表指针
linux: task_struct
winodws : eprocess
进程的三种基本状态
1.运行态,
占有cpu,并在cpu上运行
2.就绪态,
已经具备运行条件,但没有空闲cpu,而暂时不能运行
3.等待态
因等待某一件事而暂时不能运行。如等待读盘操作
状态转换
就绪 -> 运行 (调度程序选择一个新但进程运行)
运行 -> 就绪 (运行进程用完了时间片,一个高优先级进程进入就绪状态,抢占正在运行的进程)
运行 -> 等待 (当一个进程等待某个事件发生时)
1.请求os服务
2.等待i/o结果
3.等待另一进程提供信息
等待 -> 就绪 所等待的事件发生了
其他状态
创建态:已完成创建进程所必要的工作(PID,PCB),但尚未执行该进程,因为资源有限
终止态:终止执行后,进程进入该状态,可完成一些数据统计工作,资源回收
挂起态:用于调节负载,进程不占用内存空间,其进程映像交换到磁盘上
创建 -提交-> 就绪 <-超时-调度-> 运行 -释放-> 终止
^ |
| |
事件发生 等待事件
| |
阻塞 <---------------
- - - - - - - - - -> 创建 退出
| ^ ^
提交 提交 释放
| | |
就绪挂起 <-挂起-激活-> 就绪 <-超时-调度-> 运行
^ ^ |
| | |
事件出现 事件出现 |
| | |
阻塞挂起 <-挂起-激活-> 阻塞< --等待事件 -----
进程队列
1.操作系统为每一类进程建立一个或多个队列
2.队列元素为pcb
3.伴随进程状态的改变,其pcb从一个队列进入另一个队列
就绪 -> pub1 -> pcb2 -> pcb3
等待1 -> pub6 -> pcb7 -> pcb8
进程控制
原语(primitive),完成某种特定功能的一段程序,具有不可分割性或不可中断性,即原语的执行必须是连续的,在执行过程中不允许被中断
进程控制操作完成进程各状态之间的转换,由具有特定功能的原语完成
1.进程创建原语
2.进程撤销原语
3.阻塞原语
4.唤醒原语
5.挂起原语
6.激活原语
7.改变进程优先级
进程的创建
1.给新进程分配一个唯一标识以及进程控制块
2.为进程分配地址空间
3.初始化进程控制块
1.设置默认值(New)
4.设置相应的队列指针
1.如把新进程加到就绪队列链表中
进程的撤销
1.收回进程所占的资源
1.关闭打开的文件,断开网络连接,回收分配的内存
2.撤销该进程的PCB
进程阻塞
处于运行状态的进程,其运行过程中期待某一事件的发生,如等待键盘输入,等待磁盘数据传输完成,等待其他进程发送消息,当被等待的事件未发生时,由进程自己执行阻塞原语,使自己由运行态变为阻塞态
unix:wait
windows.w=WaitForSingleObject
UNIX几个进程控制操作
1. fork() 通过复制调用进程来创建新的进程,是最基本的进程建立过程
1.为子进程分配一个空闲的进程描述符
proc结构
2.分配给子进程唯一标识符pid
3.以一次一页的方式复制父进程地址空间
4.从父进程处继承共享资源,如打开的文件和当前工作目录等
5.将子进程的状态设为就绪,插入就绪队列
6.对子进程返回标识符0
7.向父进程返回子进程的pid
2. exec() 包括一系列系统调用,他们都是通过用一段新的程序代码覆盖原来的地址空间,实现进程执行代码的转换
3. wait() 提供初级进程同步状态,能使一个进程等待另外一个进程的结束
4. exit() 用来终止一个进程的运行
fork示例代码
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
void main(int argc,char*argv[])
{
pit_t pid;
pid = fork() /*创建一个子进程*/
if(pid < 0){ /*出错*/
fprintf(stderr,"fork failed");
exit(-1);
}
else if(pid == 0){/*子进程*/
execlp("/bin/ls","ls",NULL);
}
else { /*父进程*/
wait(NULL); /*父进程等待子进程结束*/
printf("child complete");
exit(0);
}
}
/*父进程*/
pid = fork() /*fork完后父进程拿到子进程的pid*/
if (pid == 0){
printf("child")
} else {
printf("parent")
}
/*子进程*/
pid = fork() /*子进程创建完后pid为0*/
if (pid ==0){
printf("child");
} else {
printf("parent")
}
进程分类
1.系统进程
2.用户进程
3.前台进程
4.后台进程
5.cpu密集型进程
6.i/o密集型进程
进程层次结构
1.UNIT进程家族树:init为根
2.windows:地位相同
进程与程序的区别
1.进程更能准确刻画并发,而程序不能
2.程序是静态的,进程是动态的
3.进程是由生命周期的,程序是相对长久的
4.一个程序可对应多个进程
5.进程具有创建其他进程的功能
进程地址空间
int myval;
int main(int argc,char*argv[])
{
myval = atoi(argv[1]);
while(1)
printf("myval is %d, loc 0x%lx\n",myval,(log)&myval)
}
同时用2个中断运行,输入不同的值,得到的虚拟地址是相同的
内核地址空间
------------
用户地址空间(展示myval的虚拟地址位置) 栈,堆,数据段(myval存在这一块的不同位置),代码段
进程映像
对进程执行活动全过程的静态描述,由进程地址空间内容,硬件寄存器内容及该进程相关的内核数据结构,内核栈组成
1.用户相关:进程地址空间(代码段,数据段,堆和栈,共享库)
2.寄存器相关:程序计数器,指令寄存器,程序状态寄存器,栈指针,通用寄存器的值)
3.内核相关:
1.静态部分:PCB及各种资源数据结构
2.动态部分:内核栈(不同进程在进入内核后使用不同的内核栈)
上下文切换
1.将cpu硬件状态从一个进程切换到另一个进程的过程称为上下文切换
2.进程运行时,其硬件状态保存在cpu上的寄存器中
1.寄存器,程序计数器,程序状态寄存器,栈指针,通用寄存器,其他控制寄存器的值
3.进程不运行时,这些寄存器的值保存在进程控制块中,PCB中,当操作系统要运行一个新的进程时,将PCB中的相关值送到对应的寄存器中