操作系统(五)
UNIX进程模型的基本结构和工作过程
1,proc 结构数组和user结构
对于每个进程,除程序代码(在UNIX中成为正文段)、数据区、栈外、每个进程的进程管理信息都存放在proc结构中,每个进程有一个proc结构和一个user结构。proc结构中存储进程不在运行态时核心也需要的东西(例如进程优先级,核心每次进行调度时可能需要查看许多进程的优先级)。所有的进程信息放在一起形成proc结构数组,放在核心数据区中。user结构中存放该进程不再运行态时核心通常不需要的信息,user结构存放在进程相应的数据段中。
2,进程的用户态和核心态
除进程0外,每个进行进程都在两种状态之一运行:核心态和用户态。当一个进程在用户态下运行而发生中断或陷入时便进入核心态。一个进程在两种不同状态下有不同特权,不同地址空间,不同的栈,不同的栈指针。它们惟一的共同点是有相同的proc结构和user结构。
3,进程终止和zombie进程
内核为每个终止子进程保存了一定量的信息,当该终止子进程的父进程调用wait活waitpid时,可以得到这些信息。这些信息至少包括进程ID、该进程的终止状态以及该进程使用的CPU时间总量。在UNIX术语中,一个已经终止、但是其父进程尚未通过wait或waitpid时来获取其信息的进程,称为僵死进程。ps命令将僵死进程的状态显示为Z。如果父进程在子进程前终止,则init进程(1号进程)就成为这些子进程的父进程(这些子进程由init进程领养)。
Linux初始过程和进程层次
进程表中的task(0)和task(1)在linux中是特别的进程,task(0)即是inittask,是系统启动时第一个产生的进程,扮演一个特殊角色。task(1)即为pid为1的进程,是linux系统中的第一个真正的进程。因为它通常执行init程序,所以也成为init进程。在系统启动后,0号进程只负责无助的系统时间的使用。即空转进程(idel process)。因此在调用等过程中需扫描进程表链接时,它通常被跳过。
Linux进程表和任务结构
在linux中进程又称任务。进程表(process table)是由NR_TASKS个task结构组成的静态数组:
struct task_struck *task[NR_TASKS];
每个进程在进程表中占有一项(一个task_struct结构)。在该表中,所有进程通过一个双向环形链相接,链头由外部变量init_task指定。
Linux进程状态
Linux中,一个任务可能处于以下几种状态之一(这些状态间的关系如图2.24所示):
(1)运行态(running):该任务是active的,而且正在非特权的用户方式下运行。该状态只能通过中断或者系统调用退出,进入特权系统方式,激活相应中断处理例程。
(2)中断处理状态(interrupt routing):当硬件发出一个中断信号时,中断处理例程被激活。该状态对应的state取值为TASK_RUNNING。
(3)系统调用期间(system call):系统调用通过软件中断启动。一个系统调用可能将相应进程挂起等待一个事件。此状态对应的state取值为TASK_RUNNING(若此状态包含等待态,则对应的取值为TASK_INTERRUPTIBLE)。
(4)等待态(waiting):进程在等待一个外部事件,只有在这个事件发生后,进程才能继续工作。
(5)从系统调用返回(return from system call):每个系统调用后自动进入该状态,每个中断处理完毕后也自动进入该状态。在该状态下,要查看是否需要调用调度程序,是否有信号需要处理。调度程序可能将该进程切换为就绪态,同时激活另一个进程。
(6)就绪态(ready):处于此状态的进程正在竞争处理机,但处理机正被另一个进程占用。
从理论上来讲,上述进程状态应该一一对应实际实现任务结构中的state取值,但是出于一些现实的考虑,state的取值与上述状态划分并不一致。
Linux中断处理机制
linux中断处理具有快中断和慢中断两种机制,这两种中断处理过程的区别主要有以下3点:
1)慢中断处理最初保存现场时,需要保存所有的寄存器值。而快中断处理最初保存现场时,只需要保存那些被常规C函数修改的寄存器的值(如果在中断处理例程中用到汇编代码,则其余寄存器也必须保存和恢复)。
2)慢中断处理时,通常不屏蔽其他中断,而快中断处理时,通常要屏蔽其他所有的中断。
3)慢中断处理完毕后,通常不立即返回被中断大的进程,而是调用调度程序,调度程序的调度结果不一定是被中断的过程,因此这种情况被成为抢先式中断。而快中断处理完毕后,通常恢复现场返回被中断的进程急促执行,称为非抢先式调度或非抢先式中断。慢中断是最常见的中断,而快中断则通常用于短时间的,不太复杂的中断处理任务。
Linux 进程调度算法
在linux中,CPU调度算法可由用户通过宏定义来选择。可选的算法包括先来先服务,时间片轮转等。Linux中还经常使用不设进程就绪队列的进程动态优先级算法。进程调度子程序schedule总是选择动态优先级最高的进程来使用CPU。
进程动态优先级调度算法有很多种,取决于动态优先级的具体含义:Linux中对进程动态优先级——task_struck结构中的counter分量的定义是:在抢先式中断调度前该进程还能运行的时间。这个时间的单位是tick。在Linux中,一个tick是10ms。
counter的值是如何产生和变化的,这与task_struct中的另一个分量priority(进程静态优先级)有关。进程静态优先级priority是在进程建立时从父进程继承来的,在一个进程整个运行期间其值保持不变,除非用户通过系统调用nice()或setpriority()来设置。进程建立时,进程动态优先级的值也是在父进程继承来的。此后在该进程存在期间,每当时钟中断发生时,当前进程的counter会减1。该递减过程在两情况下停止。
1)当进程counter值递减到0时,进程就会在时钟中断处理过程中被迫从运行态进入就绪态。但系统中处于就绪态的进程,其进程动态优先级并不一定为0。从运行态进入就绪态的进程,其动态优先级会一直保持为0,直到系统中所有的就绪态进程的动态优先级都为0。再在调度程序中为各个进程重新设计动态优先级,按照动态优先级的大小依次进入运行态运行。
2)对于处在运行态的当前进程,可能在counter值还没递减到0时,进程需要等待某个事件的发生而进入了登等待状态,处于等待态的进程,其优先级可能逐渐增加,也可能保持不变,但是不会减少。
当所有的进程的动态优先级都降为0,重新计算所有的进程的动态优先级,所有就绪进程的动态优先级都被设为进程的静态优先级。需要注意的有3点:1)并不是当一个进程的动态优先级递减为0进入就绪态之后就马上修改成为静态优先级,而是当所有的进程的静态优先级都递减为0时才一起这样做。2)所有的进程都参与了重新计算,包括所有的就绪态进程和等待态进程。3)并不是直接将静态优先级的值赋给动态优先级,而是利用一个特殊的计算公式。
p->counter = (p->counter>>1) + p->priority //p 为每个进程的task结构
这个公式的含义是:对于每个进程,将该进程的动态优先级的值右移一位,再加上该进程ID的静态优先级的值。对于就绪态的进程来说,这个公式的含义就是直接赋值。但对处于等待态的进程来说,这个公式意味着两点:等待态的进程的动态优先级会高于其静态优先级,但是不会比起静态优先级的两倍更大。
UNIX进程模型的基本结构和工作过程
1,proc 结构数组和user结构
对于每个进程,除程序代码(在UNIX中成为正文段)、数据区、栈外、每个进程的进程管理信息都存放在proc结构中,每个进程有一个proc结构和一个user结构。proc结构中存储进程不在运行态时核心也需要的东西(例如进程优先级,核心每次进行调度时可能需要查看许多进程的优先级)。所有的进程信息放在一起形成proc结构数组,放在核心数据区中。user结构中存放该进程不再运行态时核心通常不需要的信息,user结构存放在进程相应的数据段中。
2,进程的用户态和核心态
除进程0外,每个进行进程都在两种状态之一运行:核心态和用户态。当一个进程在用户态下运行而发生中断或陷入时便进入核心态。一个进程在两种不同状态下有不同特权,不同地址空间,不同的栈,不同的栈指针。它们惟一的共同点是有相同的proc结构和user结构。
3,进程终止和zombie进程
内核为每个终止子进程保存了一定量的信息,当该终止子进程的父进程调用wait活waitpid时,可以得到这些信息。这些信息至少包括进程ID、该进程的终止状态以及该进程使用的CPU时间总量。在UNIX术语中,一个已经终止、但是其父进程尚未通过wait或waitpid时来获取其信息的进程,称为僵死进程。ps命令将僵死进程的状态显示为Z。如果父进程在子进程前终止,则init进程(1号进程)就成为这些子进程的父进程(这些子进程由init进程领养)。
Linux初始过程和进程层次
进程表中的task(0)和task(1)在linux中是特别的进程,task(0)即是inittask,是系统启动时第一个产生的进程,扮演一个特殊角色。task(1)即为pid为1的进程,是linux系统中的第一个真正的进程。因为它通常执行init程序,所以也成为init进程。在系统启动后,0号进程只负责无助的系统时间的使用。即空转进程(idel process)。因此在调用等过程中需扫描进程表链接时,它通常被跳过。
Linux进程表和任务结构
在linux中进程又称任务。进程表(process table)是由NR_TASKS个task结构组成的静态数组:
struct task_struck *task[NR_TASKS];
每个进程在进程表中占有一项(一个task_struct结构)。在该表中,所有进程通过一个双向环形链相接,链头由外部变量init_task指定。
Linux进程状态
Linux中,一个任务可能处于以下几种状态之一(这些状态间的关系如图2.24所示):
(1)运行态(running):该任务是active的,而且正在非特权的用户方式下运行。该状态只能通过中断或者系统调用退出,进入特权系统方式,激活相应中断处理例程。
(2)中断处理状态(interrupt routing):当硬件发出一个中断信号时,中断处理例程被激活。该状态对应的state取值为TASK_RUNNING。
(3)系统调用期间(system call):系统调用通过软件中断启动。一个系统调用可能将相应进程挂起等待一个事件。此状态对应的state取值为TASK_RUNNING(若此状态包含等待态,则对应的取值为TASK_INTERRUPTIBLE)。
(4)等待态(waiting):进程在等待一个外部事件,只有在这个事件发生后,进程才能继续工作。
(5)从系统调用返回(return from system call):每个系统调用后自动进入该状态,每个中断处理完毕后也自动进入该状态。在该状态下,要查看是否需要调用调度程序,是否有信号需要处理。调度程序可能将该进程切换为就绪态,同时激活另一个进程。
(6)就绪态(ready):处于此状态的进程正在竞争处理机,但处理机正被另一个进程占用。
从理论上来讲,上述进程状态应该一一对应实际实现任务结构中的state取值,但是出于一些现实的考虑,state的取值与上述状态划分并不一致。
Linux中断处理机制
linux中断处理具有快中断和慢中断两种机制,这两种中断处理过程的区别主要有以下3点:
1)慢中断处理最初保存现场时,需要保存所有的寄存器值。而快中断处理最初保存现场时,只需要保存那些被常规C函数修改的寄存器的值(如果在中断处理例程中用到汇编代码,则其余寄存器也必须保存和恢复)。
2)慢中断处理时,通常不屏蔽其他中断,而快中断处理时,通常要屏蔽其他所有的中断。
3)慢中断处理完毕后,通常不立即返回被中断大的进程,而是调用调度程序,调度程序的调度结果不一定是被中断的过程,因此这种情况被成为抢先式中断。而快中断处理完毕后,通常恢复现场返回被中断的进程急促执行,称为非抢先式调度或非抢先式中断。慢中断是最常见的中断,而快中断则通常用于短时间的,不太复杂的中断处理任务。
Linux 进程调度算法
在linux中,CPU调度算法可由用户通过宏定义来选择。可选的算法包括先来先服务,时间片轮转等。Linux中还经常使用不设进程就绪队列的进程动态优先级算法。进程调度子程序schedule总是选择动态优先级最高的进程来使用CPU。
进程动态优先级调度算法有很多种,取决于动态优先级的具体含义:Linux中对进程动态优先级——task_struck结构中的counter分量的定义是:在抢先式中断调度前该进程还能运行的时间。这个时间的单位是tick。在Linux中,一个tick是10ms。
counter的值是如何产生和变化的,这与task_struct中的另一个分量priority(进程静态优先级)有关。进程静态优先级priority是在进程建立时从父进程继承来的,在一个进程整个运行期间其值保持不变,除非用户通过系统调用nice()或setpriority()来设置。进程建立时,进程动态优先级的值也是在父进程继承来的。此后在该进程存在期间,每当时钟中断发生时,当前进程的counter会减1。该递减过程在两情况下停止。
1)当进程counter值递减到0时,进程就会在时钟中断处理过程中被迫从运行态进入就绪态。但系统中处于就绪态的进程,其进程动态优先级并不一定为0。从运行态进入就绪态的进程,其动态优先级会一直保持为0,直到系统中所有的就绪态进程的动态优先级都为0。再在调度程序中为各个进程重新设计动态优先级,按照动态优先级的大小依次进入运行态运行。
2)对于处在运行态的当前进程,可能在counter值还没递减到0时,进程需要等待某个事件的发生而进入了登等待状态,处于等待态的进程,其优先级可能逐渐增加,也可能保持不变,但是不会减少。
当所有的进程的动态优先级都降为0,重新计算所有的进程的动态优先级,所有就绪进程的动态优先级都被设为进程的静态优先级。需要注意的有3点:1)并不是当一个进程的动态优先级递减为0进入就绪态之后就马上修改成为静态优先级,而是当所有的进程的静态优先级都递减为0时才一起这样做。2)所有的进程都参与了重新计算,包括所有的就绪态进程和等待态进程。3)并不是直接将静态优先级的值赋给动态优先级,而是利用一个特殊的计算公式。
p->counter = (p->counter>>1) + p->priority //p 为每个进程的task结构
这个公式的含义是:对于每个进程,将该进程的动态优先级的值右移一位,再加上该进程ID的静态优先级的值。对于就绪态的进程来说,这个公式的含义就是直接赋值。但对处于等待态的进程来说,这个公式意味着两点:等待态的进程的动态优先级会高于其静态优先级,但是不会比起静态优先级的两倍更大。