进程优先级
进程可以分为实时进程和非实时进程。
- 硬实时进程有严格的时间限制,某些任务必须在指定的时限内完成。这类进程的关键特征是使进程在可保证的时间范围内得到处理。linux在主流的内核中不支持硬实时处理。
- 软实时进程时间限制没有像硬实时进程一样那么严格,可以稍微晚一点。
- 普通进程没有时间限制,但也可以根据重要性分配优先级。
在抢占式多任务处理中,每个进程都会分配到一定时间去执行,当时间到期后会被内核收回控制权让别的进程运行,其运行环境如寄存器内容和页表会被保存起来,在之后对进程环境可完全恢复。
进程的几种状态:

- 如果进程必须等待一个事件发生,状态从运行到睡眠(或者叫阻塞)。
- 如果进程等待的事件发生了,状态从睡眠到等待(或者叫就绪)。
- 当进程被授予CPU事件后,状态就从等待到运行。
- 当进程调度器从该进程收回CPU资源时,状态就从运行到等待。
- 当进程执行终止,状态从运行到终止。
在task_struct的成员state中指明了进程的当前状态,可选用值:
- TASK_RUNNING 进程处于可运行状态,确保进程可以立即执行(等待)
- TASK_INTERRUPTIBLE 进程在等待事件或者其他资源时的睡眠状态。
- TASK_STOPPED表示进程特意(如调试器暂停)停止运行。
- TASK_TRACED
- EXIT_ZOMBIE 僵尸状态
- EXIT_DEAD
当进程终止时,父进程必须调用wait系统调用,使得内核可以释放子进程保留的资源。否则会产生僵尸进程。
用户态和核心态
进程通常处于用户态,只能访问自身的数据,不会干扰也不会察觉到系统的其他进程。如果进程想访问系统数据和功能,那就必须转换为核心态,一种方法是系统调用,另一种方法是中断。系统调用是程序主动的,中断是不可预测的。处理中断的操作一般与正在执行的进程无关,例如进入系统的网络数据包是通过中断通知,但当前运行的进程不会察觉。因为中断触发后需要快速处理,所以中断具有最高级别,可以暂停处于用户态和核心态的进程。
若系统处于核心态并处理系统调用,那么其他进程是无法夺取CPU资源的(中断可以)。
Linux提供资源限制机制,对进程使用系统资源施加限制。是task_struct中的rlim数组。其数据项为rlimit
<resource.h>
struct rlimit{
unsigned long rlim_cur;
unsigned long rlim_max;
}
rlim_cur是进程在当前的资源限制,称为软限制。
rlim_max是该限制的最大容许值,称为硬限制。
系统调用setrlimit来增减当前限制,但不能超出rlim_max指定的值。(可以通过setrlimit手册页来看详情限制。)
在Linux中,很多资源是全局的。如所有进程都是用PID标识的,所以内核必须管理一个全局PID列表。
命名空间建立了系统的不同视图

心动命名空间可以用两种方式创建:
- 用fork或clone系统调用创建新进程时。
- unshare系统调用将进程的某些部分从父进程分离。
进程ID
-
线程组ID,处于某个线程组的所有进程有统一的线程ID(TGID)。若进程没有使用线程,那么PID和TGID相同。
-
进程组ID,独立进程可以合并为进程组,进程组的pgrp属性值都是相同的,为进程组组长的PID。
-
会话,几个进程组可以合并为一个会话,会话中所有进程都有相同的会话ID,保存在task_struct的session成员中。
全局ID:是在内核本身和初始命名空间中唯一的ID号,在整个系统中是唯一的。
局部ID:属于某个特定的命名空间,不具备全局有效性,只在所属的命名空间内。
全局PID和TGID直接保存在task_struct中,都是为__kernel_pid_t类型。会话和进程组ID直接保存在用于信号处理的结构中。
进程复制
- fork是重量级调用,建立了父进程的一个完整副本,然后作为子进程执行。为了减少调用的相关工作量,Linux使用了写时复制技术。
- vfork并不创建父进程的副本,父子进程之间共享数据,在子进程退出或开始新程序之前,内核保证父进程处于堵塞状态。
- clone产生线程。
在调用fork时,内核若对父进程的每个内存页都创建一个相同的副本,这会使用掉大量内存也会在复制操作上消耗大量时间。内核可以先只是复制父进程页表,采用写时复制技术。
fork,vfork,clone的系统调用入口点分别是sys_fork,sys_vfork,sys_clone。
Linux提供的execve系统调用用于新代码替换现存程序,启动新程序。该系统调用点是sys_execve函数。
内存中保存了进程的唯一描述,并使用若干数据结构与其他进程连接起来。调度器需要完成的是调度策略和上下文切换。在多处理器系统上要避免调度器自相干扰。
网友评论