Linux进程管理

 

描述进程

进程描述符task_struct

由slab分配器分配一个thread_info结构体到进程内核栈的栈底,thread_info结构体中有一个指向task_struct的指针,task_struct中有一个int值pid来表示每个进程

进程五种状态

TASK_RUNNING:正在执行或等待执行。 TASK_INTERRUPTIBLE:处于阻塞状态,可被唤醒。 TASK_UNINTERRUPTIBLE:处于阻塞状态,不可被唤醒。 TASK_TRACED:被跟踪。 TASK_STOPPED:不在执行也不能执行。

如何组织进程

task list:进程队列,task_struct构成的双向链表。 进程树:task_struct中有一个指向它父进程的指针,还有一个存放它子进程的链表。

创建进程

写时拷贝

通过拷贝当前进程创建一个子进程。内核不复制整个地址空间,而是让父进程和子进程以只读的方式共享同一拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。实际开销只有复制父进程的页表、为子进程分配描述符。

fork()

fork() -> clone() -> do_fork() -> copy_process()

exec()

读取可执行文件,载入地址空间并开始执行。

销毁进程

exit()

1、释放占用的文件资源和部分内存; 2、为子进程寻找新的父进程; 3、打上标志EXIT_ZOMBIE,即处于不可运行状态; 4、此时它仍然占有:内核栈、thread_info结构、task_struct结构;这些是为了向父进程提供信息;

wait()

当父进程检索到这些信息,并通知内核这些已经是无用的信息时,这些内存也被释放。

线程

定义

能共享资源的进程。对线程的描述、组织和操作与进程相同。

创建线程

在调用clone()时传递一些参数来指明共享哪些资源。 共享的有:地址空间、文件系统资源、文件描述符、信号处理程序。

内核线程

独立运行在内核空间的标准进程。可以被调度,也可以被抢占。只能由内核线程创建。

进程调度

调度器类

包含多种不同的可动态添加的调度算法的模块。每种调度算法负责一类进程,按优先级排序。先选择具有最高优先级的调度算法,再由它算出执行哪个进程。

完全公平调度算法

针对普通进程。 允许每个进程运行一段时间,循环轮转,选择运行最少的进程作为下一个进程。 运行时间由目标延迟、nice值的几何加权、最小粒度决定。

时间记账

task_struct中有一个名为se的sched_entity结构体,其中有一个vruntime变量,存放程序的虚拟运行时间。虚拟运行时间的计算是经过了所有可运行进程总数的加权,单位是ns。

进程选择

目的是选择vruntime最小的进程。 使用红黑树来组织可运行进程队列,可迅速找到目标进程。

调度器入口
睡眠和唤醒

等待队列 wake_up()

上下文切换

context_switch() 1、把虚拟内存从上一个进程映射切换到新进程。 2、才上一个进程的处理器状态切换到新进程的处理器状态。包括保存、恢复栈信息和寄存器信息,还有其它任何与体系结构相关的信息。

用户抢占

1、从系统调用返回用户空间时; 2、从中断处理程序返回用户空间时。

内核抢占