0.摘要 关于Linux系统进程的分析
本文内容包括对Linux、进程、进程状态、进程调度的简述与个人理解。
1.Linux
1.1Linux是什么
Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协 议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。
2.进程
2.1进程是什么
进程:指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。
-
- 进程是程序的一次执行
- 进程是可以和别的计算并行执行
- 进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
2.2进程的特征
- 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。
- 并发性:任何进程都可以同其他进程一起并发执行。
- 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
- 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。
2.3进程的组织
task_struct 是Linux内核的一种数据结构,它被装在到RAM里并且包含着进程的信息。每个进程都把它的信息放在 task_struct 这个数据结构中, task_struct 包含了以下内容:
- 标识符:描述本进程的唯一标识符,用来区别其他进程。
- 状态:任务状态,退出代码,退出信号等。
- 优先级:相对于其他进程的优先级。
- 程序计数器:程序中即将被执行的下一条指令的地址。
- 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
- 上下文数据:进程执行时处理器的寄存器中的数据。
- I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息:可以包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
保存进程信息的数据结构叫做task_struct,并且可以在include/linux/sched.h里找到它。所以运行在系统里的进程都以task_struct链表的形式存在于内核中。
为了管理进程的创建、消亡(处理僵尸进程等操作)使用了父子、兄弟关系;
为了统一处理同一信号量,使用线程组关系;为了方便全局查找,使用了哈希表关系;
为了调度程序,使用了运行队列、等待队列数据结构。
2.4进程的分类
Linux把进程区分为实时进程和非实时进程(普通进程), 其中非实时进程进一步划分为交互式进程和批处理进程。
类型 |
描述 |
实例 |
交互式进程(interactive process) |
此类进程经常与用户进行交互,,因此需要花费很多时间等待键盘和鼠标操作。当接受了用户的输入后, 进程必须很快被唤醒, 否则用户会感觉系统反应迟钝 |
shell, 文本编辑程序和图形应用程序 |
批处理进程(batch process) |
此类进程不必与用户交互, 因此经常在后台运行. 因为这样的进程不必很快相应, 因此常受到调度程序的怠慢 |
程序语言的编译程序, 数据库搜索引擎以及科学计算 |
实时进程(real-time process) |
这些进程由很强的调度需要, 这样的进程绝不会被低优先级的进程阻塞. 并且他们的响应时间要尽可能的短 |
视频音频应用程序, 机器人控制程序以及从物理传感器上收集数据的程序 |
2.5进程标识符
知道进程的产生之后,很自然的会联想到在同一个时段系统运行的进程那么多,操作系统要怎么样对这么多的进程进行有效的管理呢?
为了有效的管理在Linux中运用了一个task_struct的数据结构对一个进程做了一个完整的描述。
Linux中对进程的描述多达300行代码,定义了非常的成员,大致可分为以下几个部分:
-进程状态(State)
-进程调度信息(Scheduling Information)
-各种标识符(Identifiers)
-进程通信有关信息(IPC)
-时间和定时器信息(Times and Timers)
-进程链接信息(Links)
-文件系统信息(File System)
-虚拟内存信息(Virtual Memory)
-页面管理信息(page)
-对称多处理器(SMP)信息
-和处理器相关的环境(上下文)信息(Processor Specific Context)
-其它信息
3.进程的状态
3.1 进程状态
volatile long state; int exit_state;
3.2 state成员的可能取值
#define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 #define __TASK_STOPPED 4 #define __TASK_TRACED 8 /* in tsk->exit_state */ #define EXIT_ZOMBIE 16 #define EXIT_DEAD 32 /* in tsk->state again */ #define TASK_DEAD 64 #define TASK_WAKEKILL 128 #define TASK_WAKING 256
3.3 进程的各个状态
TASK_RUNNING |
表示进程正在执行或者处于准备执行的状态 |
TASK_INTERRUPTIBLE |
进程因为等待某些条件处于阻塞(挂起的状态),一旦等待的条件成立,进程便会从该状态转化成就绪状态 |
TASK_UNINTERRUPTIBLE |
意思与TASK_INTERRUPTIBLE类似,但是我们传递任意信号等不能唤醒他们,只有它所等待的资源可用的时候,他才会被唤醒。 |
TASK_STOPPED |
进程被停止执行 |
TASK_TRACED |
进程被debugger等进程所监视。 |
EXIT_ZOMBIE |
进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息,此时进程成为僵尸进程 |
EXIT_DEAD |
进程被杀死,即进程的最终状态。 |
TASK_KILLABLE |
当进程处于这种可以终止的新睡眠状态中,它的运行原理类似于 TASK_UNINTERRUPTIBLE,只不过可以响应致命信号 |
3.4 状态转换图
4.进程的调度
4.1进程调度是什么
调度程序利用一部分信息决定系统中哪个进程最应该运行,并结合进程的状态信息保证系统运转的公平和高效。
这一部分信息通常包括进程的类别(普通进程还是实时进程)、进程的优先级等。
通俗的说进程的调度就是利用某些信息并且根据一种的规则来合理的决定进程的运行,那么很显然要合理高效的来组织进程运行,这种规则是至关重要的。
这种规则就是我们说的调度算法。我们后面就详细的说明调度算法。
需要强调的是调度器总是选择vruntime跑得最慢的那个进程来执行。
这就是所谓的“完全公平”。为了区别不同优先级的进程,优先级高的进程vruntime增长得慢,以至于它可能得到更多的运行机会。
4.2 CFS设计思路
思路我们可以简单的理解为根据进程的权重来分配运行时间,分配给进程的时间按照公式计算:
分配给进程的运行时间 = 调度周期 * 进程权重 / 所有进程权重之和。
4.3 CFS的数据结构
5.对操作系统进程模型的看法
经过不断的改良,Linux的调度算法从曾经的2.6内核的O(1)调度器转变为以红黑树为基本数据结构的算法。为用户带来了很好的使用体验。随着算法的逐渐完善,算法优化的空间越来越小,但我相信,经过对操作系统的 学习,今后我们一定能找到改良的突破点,或是开发出更好的算法。
6.相关资料的链接
https://blog.csdn.net/dyllove98/article/details/9281081
https://blog.csdn.net/zjf280441589/article/details/43339007
http://blog.sina.com.cn/s/blog_79e165ef0102wcvz.html
https://blog.csdn.net/fdssdfdsf/article/details/7894211