进程的一些正常状态
什么是进程
操作系统作为硬件的使用层,提供使用硬件资源的能力,进程作为操作系统使用层,
提供使用操作系统抽象出的资源层的能力。
进程:是指计算机中已运行的程序。进程本身不是基本的运行单位,而是线程的容器。
程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行
实例。
进程间的关系
linux提供一些api进行上面状态的查询 查看当前这个进程的状态
●TASK_ RUNNING (可运行状态或者可就绪状态) ;
●TASK INTERRUPTIBLE (可中断睡眠状态,又叫浅睡眠状态) ;
●TASK UNINTERRUPTIBLE (不可中断状态,又叫深度睡眠状态) ;我们可以通过ps命令查看被标记为D状态
●TASK_ STOPPED (终止状态) ;
●EXIT_ ZOMBIE (僵尸状态) ;
进程结构体
Linux内核涉及进程和程序的所有算法都围绕一个名为task_struct的数据结构建立,该结构定义在include/linux/sched.h中。这是系统中主要的一个结构。在阐述调度器的实现之前,了解一下Linux管理进程的方式是很有必要的。
task_struct包含很多成员,将进程与各个内核子系统联系,task_struct定义如下
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ 进程状态标志
void *stack; 指向内核栈
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
pid_t pid; //全局进程号
pid_t tgid; //全局线程号
struct pid_link pids[PIDTYPE_MAX]; //进程组标识符和会话标识符,进程号
struct task_struct __rcu *real_parent; /* real parent process */ 真父进程号
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */ 父进程号
struct task_struct *group_leader; /* threadgroup leader */ 指向线程组的组长
const struct cred __rcu *real_cred; /* objective and real subjective task 指向证书
* credentials (COW) */
const struct cred __rcu *cred; /* effective (overridable) subjective task*/
char comm[TASK_COMM_LEN]; //进程名称
int prio, static_prio, normal_prio; //调度策略的优先级
prio //动态优先级
static_prio//每个进程刚开始就分配了静态优先级,使用nice和set_shell来修改
normal_prio//动态优先级
unsigned int rt_priority;//实时进程优先级,不会带入之前说的值
const struct sched_class *sched_class;//表示该进程所属的调度器的类
cpumask_t cpus_allowed;//是否运行在cpu上运行
int nr_cpus_allowed;//允许这个进程在哪个cpu上运行
struct mm_struct *mm, *active_mm;//这两个指针指向内存描述符
//在进程中,mm和active_mm指向同一个内存描述符
//内核线程中mm就是空指针,当内核线程运行的时候active_mm指向进程借用一个内存描述符
struct fs_struct *fs; //指向文件系统,主要为进程根目录和当前进程工作目录
struct files_struct *files; //打来的文件列表
//下面用于做信号处理
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
struct sigpending pending;
/* ipc stuff *///下面两个用于unix信号量和共享内存
struct sysv_sem sysvsem;
struct sysv_shm sysvshm;
....}
进程优先级
1、进程优先级
总体排序 : 限期进程的优先级比实时进程要高,实时进程的优先级比普通进程要高。
➢限期进程的优先级是-1;
➢实时进程的优先级1-99,优先级数值越大,表示优先级越高;
➢普通进程的静态优先级为: 100-139, 优先级数值越小,表示优先级越高,可通过修改
nice值改变普通进程的优先级,优先级等于120加上nice值。
2、 并非所有进程都具有相同的重要性。
除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求。首先进行比较粗糙的划分,进程可以分为实时进程和非实时进程(普通进程)。
实时进程优先级(0-99)都比普通 进程的优先级(100-139)高。当系统中有实时进程运行时,普通进程几乎无法分到赶时间片(只能分到5%的CPU时间)
下面的优先级也对应了四个属性, 不同的进程使用哪个属性比较当前的优先级
如何创建进程
1用户进程
传统的UNIX中用于复制进程的系统调用是fork。但它并不是Linux为此实现的唯一调用,实际上Linux实现了3个。
(1) fork是重量级调用,因为它建立了父进程的一个完整副本,然后作为子进程执行。为减少与该调用相关的工作量,Linux使用了写时复制(copy-on-write)技术。
(2) vfork类似于fork,但并不创建父进程数据的副本。相反,父子进程之间共享数据。这节省了大量CPU时间(如果一个进程操纵共享数据,则另一个会自动注意到)。
(3) clone产生线程,可以对父子进程之间的共享、复制进行精确控制。
进程系统调用
【写时复制】
内核使用了写时复制(Copy-On-Write,COW)技术,以防止在fork执行时将父进程的所有数据
复制到子进程。在调用fork时,内核通常对父进程的每个内存页,都为子进程创建一个相同的副本。
【执行系统调用】
fork、vfork和clone系统调用的入口点分别是sys_fork、sys_vfork和sys_clone函数。其定义依赖于
具体的体系结构,因为在用户空间和内核空间之间传递参数的方法因体系结构而异。
【do_fork实现】
所有3个fork机制最终都调用kernel/fork.c中的do_fork(一个体系结构无关的函数)
2内核线程
内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程,与系统中其他进程“并行”执行(实际上,也并行于内核自身的执行)。内核线程经常称之为(内核)守护进程。它们用于执行下列任务
周期性地将修改的内存页与页来源块设备同步(例如,使用mmap的文件映射)。
• 如果内存页很少使用,则写入交换区。
• 管理延时动作(deferred action)。
• 实现文件系统的事务日志
3图片示例
上面的用户进程使用 fork() vfork() do_fork()
和内核线程中的kthread_creat() 从源码里分析都是用到了do_fork()这个函数
CFS调度器
调度器是啥
调度器 Linux内核中用来安排调度进程(-一段程序的执行过程)执行的模块称为调度器(Scheduler),它可以切换进程状态(Process status)。比如:执行、可中断睡眠、不可中断睡眠、退出、暂停等。
调度器是CPU中央处理器的管理员,主要负责完成做两件事情:
一、选择某些就绪进程来执行,
二是打断某些执行的进程让它们变为就绪状态。调度器分配CPU时间的基本依据就是进程的优先级。
上下文切换(context switch):将进程在CPU中切换执行的过程,内核承担此任务,负责重建和存储被切换掉之前的CPU状态。
调度器类定义
sched_class结构体表示调度类,定义在kernel/sched/sched.h
Linux调度类:dl_sched_class、rt_sched_class、fair_sched_class及idle_sched_class等。每个进程都有一个自己的调度策略
每个调度策略对应一种调度类
这5种调度类的优先级从高到低依次为:停机调度类、限期调度类、实时调度类、公平调度类、空闲调度
类。
●停机调度类:优先级是最高的调度类,停机进程是优先级最高的进程,可以抢占所有其它进程,其他进
程不可能抢占停机进程。
●限期调度类:最早使用优先算法,使用红黑树把进程按照绝对截止期限从小到大排序,每次调度时选择
绝对截止期限最小的进程。
●实时调度类:为每个调度优先级维护-一个队列。
●公平调度类:CFS用于一般线程 使用完全公平调度算法。完全公平调度算法引入虚拟运行时间的相关概念:虚拟运行时间=
实际运行时间*nice0对应的权重/进程的权重。
●空闲调度类:每个CPU上有一个空闲线程,即0号线程。空闲调度类优先级别最低,仅当没有其他进程可
以调度的时候,才会调度空闲线程。每个CPU的第一个PID=0线程,swapper,是一个静态线程。调度类属
于idel sched class。 一般运行在开机过程和CPU异常的时候会做dump.
Linux调度核心选择下一个合适的task运行时,会按照优先级顺序遍历调度类的pick_ next. _task函数。
进程优先级
task_ struct结构体中采用3三个成员表示进程的优先级: prio和normal_ prio表示动态优先
级, static_ prio表示进程的静态优先级。
内核将任务优先级划分,实时优先级范围是0到MAX_ RT_ PRIO-1 (即99) , 而普通进程
的静态优先级范围是从MAX_ RT_ PRIO到MAX_ PRIO-1 (即100到139) 。
这种粗糙的划分,进程可以分为实时进程和非实时进程(普通进程)
实时进程(Real-Time Process) :优先级高、需要立即被执行的进程。
普通进程(Normal Process) :优先级低、更长执行时间的进程。
进程的优先级是一I -个0–139的整数直接来表示。数字越小,优先级越高,其中优先级0-99留给实时进程,
100-139留给普通进程。
实时进程优先级(0-99)都比普通 进程的优先级(100-139)高。当系统中有实时进程
运行时,普通进程几乎无法分到赶时间片(只能分到5%的CPU时间)。
内核调度策略
有了上面的进程优先级和各种调度器类,这时候linux内核会提供一些调度策略给应用程序来选择调度器
SCHED_ NORMAL: 普通进程调度策略,使task选择CFS调度器来调度运行:
SCHED_ FIFO: 实时进程调度策略,先进先出调度没有时间片,没有更高优先级的状态下,只有等待主动
让出CPU;
SCHED_ RR:实时进程调度策略,时间片轮转,进程使用完时间片之后加入优先级对应运行队列当中的尾
部,把CPU让给同等优先级的其它进程;
SCHED_ BATCH:普通进程调度策略,批量处理,使task选择CFS调度器来调度运行;
SCHED_ JIDLE: 普通进程调度策略,使task以最低优先级选择CFS调度器来调度运行:
SCHED_ DEADLINE: 限期进程调度策略,使task选择Deadline调度 器来调度运行;
备注:其中stop调度器和DLE-task调度器,,仅使用于内核,用户没有办法进行选择。
在一个进程的结构体中,下面这个属性来表示这个进程所属的调度器类
完全公平调度器CFS
完全公平调度算法体现在对待每个进程都是公平的,让每个进程都运行一段相同的时间片,这就是基于时间片轮询调度算法。
CFS定义一种新调度模型,它给cfs_rq(cfs的run queue)中的每一个进程都设置一个虚拟时钟-virtual runtime(vruntime)。如果一个进程得以执行,随着执行时间的不断增长,其vruntime也将不断增大,没有得到执行的进程vruntime将保持不变
用进程结构体中下面的属性来表示调度的关系 上面图片中的 具体成员: prio 、 normal prio、static prio、rt priority等。
实际运行时间
CFS是Completely Fair Scheduler简称,完全公平调度器。在实际当中必须会有进程优先级高或者进程优先级低,CFS调度器引入权重,使用权重代表进程的优先级,各个进程按照权重比例分配CPU时间。
假设有2个进程X和Y,X权重为1024,Y权重为2048。
X获得CPU时间比例为: 1024/(1024+2048)=33%左右
Y获得CPU时间比例为: 2048/(1024+2048)-66%左右
在引入权重之后分配给进程的时间计算公式如下:
实际运行时间=调度曲“进程权重/所有进程权重之和。
虚拟运行时间
虚拟运行时间=实际运行时间NICE_ 0_ LOAD/进程权重= (调度周期进程权重/所有进程权重之后)
NICE_ 0_ LOAD/进程权重=调度周期1024/所有进程总权重.
在一个调度周期里面,所有进程的虚拟运行时间是相同的,所以在进程调度时,只需要找到虚拟运行时间
最小的进程调度运行即可
主调度器和周期性调度器
进程调度器任务:合理分配CPU赶时间给运行的进程。调度器目标:有效地分配CPU时间片。
主调度器:通过调用schedule()函数来完成进程的选择和切换。
周期性调度器:根据频率自动调用scheduler tick函数, 作用根据进程运行时间触发调度。
上下文切换:主要做两个事情(切换地址空间、切换寄存器和栈空间)。
左边的cpu和调度器有上下文切换根据
下面有个选择进程 选择进程根据不同的调度类来选择进程 再放到调度器里面进行处理
调度类来判断接下来运行哪个进程
文章来源:https://www.toymoban.com/news/detail-498350.html
总结
调度器来分配cpu接下来执行的进程,根据进程的不一样分配不同的调度策略
不同的调度策略影响进程占用的cpu时间片
当有限期进程 直接优先 有实时进程 普通进程差不多只有百分之5的调用空间
当只有普通进程的时候,才开始看看是不是能在cfs下面进行一些公平的调度文章来源地址https://www.toymoban.com/news/detail-498350.html
到了这里,关于01.4进程原理和系统调用--->经典的CFS调度器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!