Linux系统编程——进程控制(一)
一 进程的基本概念
查看进程信息命令ps,参数如下:
- -e:列出所有进程
- -f:显示进程全部信息
- -h:不现实进程标题列出所有进程
- -l:以长格式显示进程
- -w:以宽格式显示进程
- -a:显示终端上所有进程,包括其他用户进程
- -r:只显示正在运行的进程
- -x:显示没有控制终端的进程
进程的状态和状态转换
进程在生存周期中呈现出各种状态及状态的转换,这些信息反映了进程获取系统资源的情况。Linux系统的进程状态模型见下表:
状态名称 | 说明 |
---|---|
创建状态 | 进程正在被内核创建 |
就绪态 | 进程还未开始执行,但相关数据已被创建,只要内核调度就立即执行 |
内核态 | 进程在内核态下运行,被调度上CPU执行 |
用户态 | 进程在用户态下运行,等待被调度上CPU执行 |
睡眠 | 进程正在睡眠,等待系统资源或相关信号唤醒 |
唤醒 | 正在睡眠的进程收到Linux内核唤醒的信号 |
被抢先 | 具有更高优先级的进程强制获得进程的CPU时钟周期 |
僵死状态 | 进程通过系统调用结束,进程不再存在,但在进程表项中仍有记录,该记录可由父进程收集 |
1.子进程被Linux内核调入CPU执行的过程
父进程创建子进程,子进程的创建执行过程如下图所示:
说明如下:
- 父进程同fork系统调用创建子进程
- 子进程被创建后,处于创建状态
- 内核为子进程配置数据结构
- 若内存空间足够,子进程在内核中就绪,否则在swap分区就绪。进程处于就绪态,等待Linux内核调度
- Linux内核会为子进程分配CPU时钟周期,在合适的时间将子进程调度上CPU运行。此时子进程处于内核态,开始运行
- 被分配的CPU时钟周期结束时,Linux内核再次调度子进程,将子进程调出CPU,子进程进入用户态
- 待子进程被分配到下一个CPU时钟周期到来,Linux内核将子进程调度到CPU运行,子进程进入内核态。如果有其他进程获得更高优先级,子进程的时钟周期可能会被抢占,这时又会回到用户态
2.子进程进入睡眠状态
子进程在运行时,如果请求的资源得不到满足将进入睡眠态(等待态)。睡眠态的子进程被从内存调换到Swap分区。如果该资源被释放,子进程将被调入内存,继续以系统状态执行,如下图所示:
3.子进程结束
子进程可以通过exit系统调用结束,这时子进程进入僵死状态,生命周期结束,如图所示:
子进程在内核中的数据结构又被称为上下文。上下文包括3个部分:
- 用户级上下文:子进程用户空间的内容
- 寄存器上下文:子进程运行时装入CPU寄存器的内容
- 系统级上下文:子进程在Linux内核中的数据结构
子进程切换时,CPU收到一个软中断,这时上下文将被保存,称之为保存现场。子进程再次运行时,上下文被还原到相关位置,称之为还原现场。整个过程称为上下文切换。保存上下文的数据空间称为u区,是Linux内核为进程分配的存储空间。
内核在以下情况会进行上下文切换操作:
- 子进程进入睡眠状态时
- 子进程时钟周期结束,被转为用户态时
- 子进程再次被调度上CPU运行,转为内核态时
- 子进程僵死时
2.进程控制
Linux系统中,用户创建子进程的唯一方法就是使用fork系统调用。流程图如下图所示:
说明:
- Linux内核在进程表中为子进程分配一个表项
- 分配进程标识PID
- 子进程表项的内容来自于父进程,fork系统调用会将父进程的进程表项复制为副本,并分配给子进程
- Linux内核使父进程的文件表和索引表的节点自增1
- 创建用户级上下文,将父进程上下文复制到子进程的上下文空间中
- fork系统调用结束后,子进程的PID呗返回给父进程,子进程获得的值为0
进程控制:
- exit系统调用:结束进程。内核将删除进程上下文,但保留进程表项,进程处于僵死状态。待合适时,再删除进程表项中的内容,释放进程PID。
- wait系统调用:父进程与子进程的同步。父进程调用wait后,父进程的执行被阻断,直到子进程进入僵死状态。这时,子进程的退出参数可通过wait函数返回给父进程。wait系统调用常被用来判断子进程是否已结束。
- exec系统调用:运行一个可执行文件。会结束原有进程,使用更新上下文的内容,并从头开始执行一个新的进程,两个进程之间并无父子关系。
3.进程调度
Linux系统是分时操作系统。Linux内核可同时执行多个进程,并为每个进程分配CPU时钟周期(时间片轮转?)