0%

Linux进程

进程

进程是什么?进程是操作系统分配内存、CPU等资源的基本单位。线程这是进程的进一步抽象,一个进程可以分为线程与资源集合。

在Linux中,并没有进程与线程的严格区分,在内核看来线程与进程一样,只不过是与其他一些进程共享内存等某些资源。

进程描述符

在Linux内核中,通过task_struct这个结构体来描述进程,其中包含了许多有关进程的信息,例如进程的状态、线程信息、优先级等。

进程状态

运行TASK_RUNNING

这个状态说明进程可以获取时间片来运行,但是并不意味着该进程的指令正在执行或者获得了CPU资源,只能说是可以被调度执行。

可中断等待TASK_INTERRUPTINLE

进程处于等待状态,不会被调度执行。当等待的资源可用,系统发送一个硬中断,或者受到一个信号都可以唤醒进程进入TASK_RUNNING状态。

不可中断等待状态

与可中断等待的唯一区别就是不能够被信号唤醒。通常用于特殊情况,例如打开设备文件时,相应的设备驱动程序开始探测相应的硬件设备,这个过程中,驱动程序是不能够被中断的。

暂停状态

进程暂停执行

跟踪状态

进程的执行被调试器暂停

僵死状态

表示进程执行被终止,但是其夫进程还未调用wait4或waitpid系统调用来返回有关终止进程的信息。

僵死撤销状态

表示进程的最终状态,父进程已经调用wait4或者waitpid

不可交互等待状态

进程处于等待状态并且无论它时是否可以交互都不提供任何信息。

死亡状态

特殊进程

进程0与进程1是两个特殊进程,进程0是idle进程,当没有其他进程处于TASK_RUNNING状态时,该进程就会被执行。CPU的空闲时间其实就是这个idle进程的运行时间。进程1则是init进程,init进程是用户空间的首个进程,用于孵化其他进程。

进程的内核栈

进程是不断变化的实体,内核为每个进程都分配了一个固定大小的内核栈,用来保存进程在内核态的函数调用信息以及进程描述符。

获取进程描述符

进程描述符可以从内核栈中获取,系统已经定义好了宏用来获取进程描述符。

进程创建

基本步骤:

  1. 查找可执行程序
  2. fork自身
  3. 子进程执行exec()装入该程序

fork()能够让进程复制一个与自身完全一样的进程,exec()则会读取一个外部程序来代替自身。

fork()

fork()会创建一个与自身完全一样的进程,包括各种资源。因此如果不优化fork的话,每次创建进程都会花费很大的开销。

因此,Linux内核对fork进行了优化,使之不完全复制父进程的资源,只复制页表,而且采取了写时复制的策略,让子进程在修改资源的时候复制一份副本,修改之后再回写,这其实跟Java的多线程内存共享机制是一样的。

vfork()

vfork()其实跟优化之后的fork()差不多,只不过vfork()连页表也不会复制。

clone()

clone()fork()最大的不同是,clone()可以选择性地复制父进程的资源,甚至可以让旧进程与新进程不再是父子关系,而是兄弟关系。

内核线程

内核线程就是运行在内核态的线程,普通的线程进入到内核态需要经过系统调用,但是内核线程不需要。