进程的管理与调度
进程管理
进程描述符及任务结构
进程存放在叫做任务队列(tasklist)的双向循环链表中。链表中的每一项包含一个具体进程的所有信息,类型为task_struct,称为进程描述符(process descriptor),该结构定义在<linux/sched.h>文件中。
Linux通过slab分配器分配task_struct结构,这样能达到对象复用和缓存着色(cache coloring)的目的。另一方面,为了避免使用额外的寄存器存储专门记录,让像x86这样寄存器较少的硬件体系结构只要通过栈指针就能计算出task_struct的位置,该结构为thread_info,在文件<asm/thread_info.h>中定义。
Linux中可以用ps命令查看所有进程的信息。
进程状态
task_struct中的state描述进程的当前状态。进程的状态一共有5种,而进程必然处于其中一种状态:
1)TASK_RUNNING(运行)——进程是可执行的,它或者正在执行,或者在运行队列中等待执行。这是进程在用户空间中执行唯一可能的状态;也可以应用到内核空间中正在执行的进程。
2)TASK_INTERRUPTIBLE(可中断)——进程正在睡眠(也就是说它被阻塞)等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行,处于此状态的进程也会因为接收到信号而提前被唤醒并投入运行。
3)TASK_UNINTERRUPTIBLE(不可中断)——除了不会因为接收到信号而被唤醒从而投入运行外,这个状态与可打断状态相同。这个状态通常在进程必须在等待时不受干扰或等待事件很快就会发生时出现。由于处于此状态的任务对信号不作响应,所以较之可中断状态,使用得较少。
4)TASK_ZOMBIE(僵死)——该进程已经结束了,但是其父进程还没有调用wait4()系统调用。为了父进程能够获知它的消息,子进程的进程描述符仍然被保留着。一旦父进程调用了wait4(),进程描述符就会被释放。
5)TASK_STOPPED(停止)——进程停止执行,进程没有投入运行也不能投入运行。通常这种状态发生在接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。
需要调整进程的状态,最好使用set_task_state(task, state)函数,在必要的时候,它会设置内存屏障来强制其他处理器作重新排序(SMP)。
进程的各个状态之间的转化构成了进程的整个生命周期,下图来自http://www.cnblogs.com/wang_yb/archive/2012/08/20/2647912.html。
进程的创建
在Linux系统中,所有的进程都是PID为1的init进程的后代。内核在系统启动的最后阶段启动init进程。该进程读取系统的初始化脚本(initscript)并执行其他的相关程序,最终完成系统启动的整个进程。
Linux提供两个函数去处理进程的创建和执行:fork()和exec()