进程概念
程序,指的是一个静态文件,只占用磁盘空间,里面的内容是待处理的计算机指令,数据;进程是运行起来的程序,需要占用内存,总线,cpu等系统资源。
并发
假设操作系统中有3个进程在运行,如上图所示,CPU会为每个进程分配时间片,每个进程在运行了一个时间片后将会产生时钟中断(时钟滴答),产生中断后将切换到下一个进程执行,以此类推,执行完最后一个后,从进程1执行剩下未执行完的指令(上下文切换),以此类推。
PCB进程控制块
每个进程运行时都会产生一个虚拟内存,如上图所示,每个进程在内核空间中都会有一个属于自己的PCB进程控制块用于记录当前进程的一些信息,如进程名,运行时间,进程编号等。注意:在物理内存中不同进程的PCB将放在同一块区域,但是不会相互覆盖,这样方便了进程间通信。
PCB进程控制块在源码/inlucde/linux/sched.h中被定义,名字为task_stuct 其主要功能如下:
1.记录进程ID;
2.记录进程状态:初始态(刚产生时的状态),就绪态(准备工作完成时的状态),运行态,挂起态(被挂起的进程会主动让出CPU,会被除CPU以外的资源来唤醒),死亡态等;
3.记录进程进行切换时需要保存的寄存器信息;
4.记录虚拟地址和物理地址的映射信息,是MMU记录的;
5.描述控制终端是否需要被占用;
6.记录当前控制目录;
7.umask掩码;
8.文件描述符表(记录文件描述符);
9.用户id,组id;
10.进程可以使用的资源上限。
进程的生老病死
就绪态:
当程序被执行或者他的父进程调用fork () 后该进程进入就绪态;就绪态只是准备完毕,还没有真正的运行起来,有可能正在排队等待CPU来调用它。
运行态:
进程从就绪态被CPU选中(系统调度)处理进程中的指令,该状态为运行态;
内核中的函数sched()被称为系统调度器,他会根据各种参数(优先级、等待时间...)来选择一个进程到CPU中执行其指令;
如果进程运行的过程中,他的时间片耗尽,将会被放回到就绪态的队列中重新排队,等待下一次被调用(放到队尾);
如果一个进程的时间片还没有耗尽,但是有可能会被更高优先级的进程抢占CPU,则当前进程也会被放回到就绪态的队列中 ( 放到队头 ) 。
睡眠态、挂起态:
进程在运行的过程中可能由于某些资源暂时不能获得,则会被设置为睡眠态、挂起态;
TASK_INTERRUPIBLE 在睡眠的过程中可以响应信号(浅睡眠),一般用在等待某个资源,当资源获得是会被唤醒从新回到就绪状态等待CPU调用;
TASK_UNINTERRUPIBLE 在睡眠是不会响应信号(称为深度睡眠),一般与硬件相关。
暂停态:
当进程在运行的过程中收到一个SIGSTOP或者SIGTSTP的信号时将会被设置为暂停态;
在暂停态中将不参与下一次的调度(没有在就绪的队列中),但是已经获得的系统资源不会被释放;
直到收到SIGCONT的信号才会继续回到就绪态的队列中继续等待CPU调度。
僵尸态:
进程退出之后会进入僵尸态,在这个尸体中会存放该进程的所有信息,包括他是否正常死亡,退出值,异常退出值,被谁杀死的;
父进程可以调用函数wait() / waitpid() 来查看子进程的死亡信息,顺便把子进程从僵尸态设置为死亡态。
死亡态:
由父进程调用wait/waitpid后,该进程才会进入死亡态;
不是所有的父进程都记得去帮自己的孩子收拾尸体,有可能父进程先结束,然后子进程才结束;
如果父进程比子进程早退出的话,子进程进入僵尸态的时候将会由祖父进程 init来帮他收拾,从而避免系统中出现大量的僵尸。
注意:在主函数return将退出进程。而调用exit(),无论程序运行在哪里都将退出进程。