相关: os 0916 week2
进程切换 (内核当中的
上下文切换,暂停当前运行进程,从运行态变成其他状态;调度另一个进程从就绪状态变成运行状态。 要求:
- 切换前,保存进程上下文
- 切换后,恢复进程上下文
- 快速切换。频繁的操作。系统运行效率。汇编实现。 进程生命周期的信息:
- 寄存器
- cpu状态
- 内存地址空间(大部分不用保存)
进程控制块 PCB:内核的进程状态记录
- 内核为每个进程维护了对应的进程控制块, 保存信息
- 内核将相同状态的进程的PCB放置在同一队列, 如何组织
- 就绪队列
- I/O等待队列
- 每个设备一个队列,磁带0/1;磁盘0
- 僵尸队列
后面三个为用户提供的系统调用服务
进程 创建
fork() exec()
fork()
父子进程,pid不同。
- 复制父进程的所有变量和内存
- 复制父进程的所有CPU寄存器(有一个寄存器除外)
- 返回值不同,子进程返回0,父进程返回子进程的pid.
- 地址空间的复制。 代码 数据 堆栈 除了数据的childpid部分区别。
exec() 程序加载和执行
系统调用exec()加载可执行的新程序取代当前运行进程
把整个地址空间换掉。代码 数据堆栈。
fork的开销
对子进程分配内存,复制父进程的内存和cpu寄存器到子进程里,开销昂贵。 在大多数情况下,我们调用fork之后调用execm在fork()操作中内存复制是没有作用的,子进程可能关闭打开的文件和连接。为什么不能结合它们在一个调用中? vfork() 创建进程时,不再创建一个同样的内存映像,一些时候称为轻量级fork,子进程应该几乎立即调用exec,现在使用cow技术。
进程加载
- 允许进程加载一个完全不同的程序,并从main开始执行。(即_start)
- 允许进程加载时指定启动参数(argc,argv)
- exec调用成功时
- 它是相同的进程
- 但是运行了不同的程序
- 代码段、堆栈和数据等完全重写
进程等待与退出 父子 关系
父进程等待子进程
- wait() 系统调用用于父进程等待子进程的结束
- 子进程结束时通过exit()向父进程返回一个值
- 父进程通过wait()接受并处理返回值
- wait()系统调用的功能
- 有子进程存活时,父进程进入等待状态,等待子进程的返回结果 当某子进程调用exit时,唤醒父进程,将exit返回值作为父进程中wait的返回值
- 有僵尸子进程等待时,wait()立即返回其中的某一个值??
- 无子进程存活时,wait()立刻返回
有序终止 exit()
- 进程结束执行时调用exit(),完成进程资源回收
- exit()系统调用的功能
- 将调用参数作为进程的“结果”
- 资源回收,关闭打开的文件,分配的内存,创建的内核相关数据结构
- 检查父进程是否还存活
- 若存活,保留结果的值直到父进程需要它,进入僵尸 zombie/defunct状态
- 若没有,释放所有的数据结构,进程结束
- 清理所有等待的僵尸进程
- 进程终止时最终的垃圾收集