1.Linux是如何组织进程的。
*进程的概念:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
*下面用一张图来表示一个程序从编写到最终运行的过程:
*进程是一个动态的过程,既然会产生进程,那么进程也会消失,即死亡。每个进程都是有其父进程产生,若子进程结束后,父进程会回收其资源。若子进程的父进程先被结束,那么子进程就会进入孤儿态,其会被系统的1号进程回收其资源。
shell命令ps -lA可以查看当前系统的进程,例如:
2.进程状态如何转换。
* Linux进程状态有:
TASK_RUNNING : 就绪态或者运行态,进程就绪可以运行,但是不一定正在占有CPU,对应进程状态的R
TASK_INTERRUPTIBLE:睡眠态,但是进程处于浅度睡眠,可以响应信号,一般是进程主动sleep进入的状态,对应进程状态S
TASK_UNINTERRUPTIBLE:睡眠态,深度睡眠,不响应信号,典型场景是进程获取信号量阻塞,对应进程状态D
TASK_ZOMBIE:僵尸态,进程已退出或者结束,但是父进程还不知道,没有回收时的状态,对应进程状态Z
TASK_STOPED:停止,调试状态,对应进程状态T
*进程调度时机:
进程调度会引起进程状态转换,由上图可知如下情况会触发调度,进程终止或进程睡眠时主动exit或sleep释放CPU;
浅度睡眠的进程被CFS调度选中唤醒,深度睡眠进程由于信号量,锁等的释放而被唤醒;进程收到信号量等;还有一种最常见的中断,异常。
3.进程是如何调度的。
*进程调度的含义
操作系统要实现多进程,进程调度必不可少。进程调度是对TASK_RUNNING状态的进程进行调度,需要进行调度的进程必须是可运行状态的。调度程序负责决定哪个进程投入运行,何时运行及运行多长时间。进程调度程序就是在可运行态进程之间分配有限的处理器时间资源的内核子系统。
*进程调度的管理
操作系统需要一个管理单元,负责调度进程,由管理单元来决定下一刻应该由谁使用CPU,这里充当管理单元的就是进程调度器。进程调度器的任务就是合理分配CPU时间给运行的进程。下面介绍进程的分类,来更好的介绍进程调度是怎样的一种模式。
-
I/O-bound:指大部分的状况是CPU在等待I/O(硬盘/内存)的读/写,通常会花费很多时间等待I/O操作的完成,此时CPU Loading不高。
-
CPU-bound:计算密集型,与上一种密集型类似,此类型需要大量的CPU时间进行运算,对于对I/O的读/写在很短的时间内就能完成,大部分的状况是 CPU Loading 100%,例如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中,绝大部份时间用在三角函数和开根号的计算,便是属于CPU-bound的程序。
-
交互式进程:顾名思义,该类型需要经常与用户进行交互,可能需要花费很长时间等待用户输入操作,且要求在很短的时间内做出响应,如图形应用程序,shell等。
-
批处理进程:此类型不需要与用户交互,通常是在后台运行完成,不要求即时响应,典型的例子有:程序的编译,科学计算等。
-
实时进程:响应的时间要短,有实时需求,不会被低优先级中断,例如视频或者音频的播放,机械的控制等。
*
进程提供了两种优先级,一种是普通的进程优先级,第二个是实时优先级。前者适用SCHED_NORMAL调度策略,后者可选SCHED_FIFO或SCHED_RR调度策略。任何时候,实时进程的优先级都高于普通进程,实时进程只会被更高级的实时进程抢占,同级实时进程之间是按照FIFO(一次机会做完)或者RR(多次轮转)规则调度的。
实时进程的调度
实时进程,只有静态优先级,因为内核不会再根据休眠等因素对其静态优先级做调整,其范围在0~MAX_RT_PRIO-1间。默认MAX_RT_PRIO配置为100,也即,默认的实时优先级范围是0~99。而nice值,影响的是优先级在MAX_RT_PRIO~MAX_RT_PRIO+40范围内的进程。
不同与普通进程,系统调度时,实时优先级高的进程总是先于优先级低的进程执行。知道实时优先级高的实时进程无法执行。实时进程总是被认为处于活动状态。如果有数个 优先级相同的实时进程,那么系统就会按照进程出现在队列上的顺序选择进程。假设当前CPU运行的实时进程A的优先级为a,而此时有个优先级为b的实时进程B进入可运行状态,那么只要b<a,系统将中断A的执行,而优先执行B,直到B无法执行(无论A,B为何种实时进程)。
不同调度策略的实时进程只有在相同优先级时才有可比性:
1. 对于FIFO的进程,意味着只有当前进程执行完毕才会轮到其他进程执行。由此可见相当霸道。
2. 对于RR的进程。一旦时间片消耗完毕,则会将该进程置于队列的末尾,然后运行其他相同优先级的进程,如果没有其他相同优先级的进程,则该进程会继续执行。
,对于实时进程,高优先级的进程就是大爷。它执行到没法执行了,才轮到低优先级的进程执行。等级制度相当森严啊。
非实时进程调度
Linux对普通的进程,根据动态优先级进行调度。而动态优先级是由静态优先级(static_prio)调整而来。Linux下,静态优先级是用户不可见的,隐藏在内核中。而内核提供给用户一个可以影响静态优先级的接口,那就是nice值,两者关系如下:
static_prio=MAX_RT_PRIO +nice+ 20
nice值的范围是-20~19,因而静态优先级范围在100~139之间。nice数值越大就使得static_prio越大,最终进程优先级就越低。
ps -el 命令执行结果:NI列显示的每个进程的nice值,PRI是进程的优先级(如果是实时进程就是静态优先级,如果是非实时进程,就是动态优先级)
而进程的时间片就是完全依赖 static_prio 定制的,见下图,摘自《深入理解linux内核》,
我们前面也说了,系统调度时,还会考虑其他因素,因而会计算出一个叫进程动态优先级的东西,根据此来实施调度。因为,不仅要考虑静态优先级,也要考虑进程的属性。例如如果进程属于交互式进程,那么可以适当的调高它的优先级,使得界面反应地更加迅速,从而使用户得到更好的体验。Linux2.6 在这方面有了较大的提高。Linux2.6认为,交互式进程可以从平均睡眠时间这样一个measurement进行判断。进程过去的睡眠时间越多,则越有可能属于交互式进程。则系统调度时,会给该进程更多的奖励(bonus),以便该进程有更多的机会能够执行。奖励(bonus)从0到10不等。
系统会严格按照动态优先级高低的顺序安排进程执行。动态优先级高的进程进入非运行状态,或者时间片消耗完毕才会轮到动态优先级较低的进程执行。动态优先级的计算主要考虑两个因素:静态优先级,进程的平均睡眠时间也即bonus。计算公式如下,
dynamic_prio = max (100, min (static_prio - bonus + 5, 139))
在调度时,Linux2.6 使用了一个小小的trick,就是算法中经典的空间换时间的思想,使得计算最优进程能够在O(1)的时间内完成。
*调度器类
*Linux进程状态机
依据其调度策略的不同实现了5个调度器类
-
stop_sched_class:发生在cpu_stop_cpu_callback 进行cpu之间任务migration,HOTPLUG_CPU的情况下关闭任务,不需要调度普通进程。
-
dl_sched_class:采用EDF最早截至时间优先算法调度实时进程,对应调度策略为SCHED_DEADLINE。
-
rt_sched_class:采用提供 Roound-Robin算法或者FIFO算法调度实时进程,具体调度策略由进程的task_struct->policy指定,对应的调度策略为SCHED_FIFO, SCHED_RR。
-
fair_sched_clas:采用CFS算法调度普通的非实时进程,对应的调度策略为SCHED_NORMAL, SCHED_BATCH。
-
idle_sched_class:采用CFS算法调度idle进程, 每个cup的第一个pid=0线程:swapper,是一个静态线程。调度类属于:idel_sched_class,所以在ps里面是看不到的。一般运行在开机过程和cpu异常的时候做dump,对应的调度策略为SCHED_IDLE。
*Linux进程状态机
4.对该操作系统进程模型的看法。
*有效管理系统资源,提高系统资源使用效率