一篇文章带你熟悉操作系统中进程描述、组织、创建、等待和终止
目录
一、背景知识
1.冯诺依曼体系
说到操作系统就不能不知道“冯诺伊曼体系”
所有的输入、输出设备都只能和内存直接沟通,即外设要输入或输出数据只能写入内存或者从内存中读取。
2.操作系统(OS)
大致包括内核(内存管理、进程管理、文件管理、驱动管理)和其他程序(函数库、shell程序等)。
目的:向上为用户程序提供良好的执行环境,适当暴露一些接口;向下与硬件交互,管理所有的软硬件资源。可以说操作系统就是一款搞管理的软件。
如何管理?以进程管理为例,首先要对进程进行描述,后将进程组织起来。
二、进程的描述
程序的一次动态执行过程,即程序就是存储设备(硬盘)上的文件加载到内存中变成进程,进程被放在内存中,被操作系统管理,让操作系统描述它并管理。进程有各种状态,运行期间可以被切换,受调度器调度,有生命周期存在。
进程的信息被放在一个进程控制块(Process Control Block)的结构体中,Linux中的PCB为task_struct。
task_struct中有:
1.pid进程的唯一标识符,0号进程是内核进程,它创建了1号进程,是它将进程从物理内存搬到磁盘,也能从磁盘搬到物理内存中
2.进程的状态:
R运行状态:进程在运行中或者在运行队列中。
S休眠状态:也成为可中断休眠状态
D深度休眠状态:等待IO结束否则kill不能杀死
Z僵尸状态:
T停止状态:kill -SIGSTOP/kill -SIGTSTP 进程pid 进程pid将进程变成停止状态 ;kill -SIGCONT (kill -l 查看所有系统支持的信号列表)
Z僵尸进程:子进程退出且父进程仍在运行但没有读取子进程进程的退出返回的代码,子进程就会产生僵尸进程,一直等待直到父进程读取退出状态的代码。
僵尸进程的危害:子进程一直等待,子进程的退出状态也在PCB中,PCB依然需要维护,光创建不回收一直维护就会造成内存泄漏
3.优先级,为了竞争有限内存,有限CPU调度器根据优先级判断。
使用指令 ps -l就可找到进程的优先级PRI 。值得注意的是进程的优先级是由PRI和NI(修正数值)共同决定的,新的PRI是旧的PRI加上NI的得到的。NIce值取值范围-20到19。
程序运行之前调整nice值用nice [-n] 数值 可执行程序
程序运行之后调整nice值用renice [-n] 数值 [-g/-p/-u] 标识符
4.内存指针:找到需要运行代码
5.上下文信息(进程切换的正常进行)、状态退出时退出父进程没有读取子进程的退出返回代码)一直维持这个状态,可用的资源越来越少、程序计数器(进程切换时CPU中EIP会被覆盖,上一个的EIP就保存在内存中的程序计数器中)、
6.记账信息(时间尽可能的均衡)。
孤儿进程:父进程先退出,子进程后退出就让子进程变成了孤儿进程,进程孤儿后会被1号进程init进程回收。
每个进程都有自己的虚拟地址空间。
三、进程的组织
用链表和树,pcb结构体作为节点。
四、进程的创建
分配一个PID,创建PCB(拷贝父进程中PCB的绝大部分),给子进程分配资源(多了一套代码和数据,将地址空间用页表映射到物理空间中实际上子进程代码和父进程是共享,数据以写实拷贝的方式各自私有) ,复制父进程地址空间。
1.fork:一次调用两个返回值,父进程返回子进程进程ID,子进程返回0,父子进程都从fork之后执行,没有先后顺序但是子进程先结束。
2.vfork:子进程先执行,当子进程调用exit或者execv时才调用父进程
五、进程的等待
必要性:子进程退出,父进程不读取子进程的退出状态就会造成僵尸进程,必须等回收子进程资源,获得子进程的退出信息因此造成内存泄漏所以要按照特定顺序退出。
子进程优先退出,父进程后退出
父进程先退出子进程变成孤儿进程,父进程还存在但不读取子进程的退出状态变成僵尸进程
1.pid_t wait(int *status)返回值是成功等待任意一个子进程返回进程pid,失败返回-1,阻塞式等待
2.pid_t waitpid(pid_t pid, int *status, int options) 指定等待某个特定pid的进程,opthions为0时为阻塞式等待options为WNOHANG时轮询式非阻塞访问
其中status是位图的结构,其中分为低八位和次低八位。参数int * status是一种输出型参数因为进程运行时都是相互独立的,用户不能用父进程拿到子进程的进程退出信息,调用wait进入操作系统,由操作系统来找到子进程,把子进程的退出信息拿出来拷贝到用户区,需要缓冲区保存退出码和收到的信号。
waitpid(-1, &status, 0) == wait(&status)
六、进程的终止
1.正确退出
exit(int status)终止进程:在程序任何地方调用exit都会导致进程退出,终止前有刷新缓冲区,关闭文件描述符等操作。
_exit(int status):进程强制终止,没有刷新缓冲区,关闭文件描述符等
main函数return才表示进程结束了
其中参数 status虽然是int但只有低八位可以使用exit(-1)的值使用echo $? 显示出的值为255
2.进程错误退出
Ctrl +c 收到信号等
WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。
WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值