Cpu是如何选择线程的?
Cpu是如何选择线程的?
linux中线程存放格式
linux中线程与进程对应的结构体都是task_struct
唯一不同的点在于线程存放的东西少了点(由于一个进程中的线程们是共享一定数据的那些东西就直接存在进程了,如内存地址空间、代码段、文件描述符等),之后将task_struct称为任务
优先级
linux中任务的优先级跨度为0~139,大致分为两大类(记好了,是两大类,与之后调用类是3种有区别):
- 实时任务
- 普通任务
优先级越低,执行顺序越优先
0-99为实时任务
100-139为普通任务
调用类
共分为3大类(目的是为了让linux中的高优先级任务优先执行):
deadline与realtime都是针对实时任务的,于是调用类为3类,而优先级大体分两类
SCHED_DEADLINE:是根据dealine来决定调用优先级的,
即哪个快要超时了,cpu则先选哪个
SCHED_FIFO: 先到先调用嘛,队列思想
SCHED_RR: (有点忘了)对于相同优先级的任务,轮流着运行,每个任务都有一定的时间片,当用完时间片且为执行完会被放回队尾,以保证相同优先级任务的公平性,但高优先级的可插队(可抢占低优先级的任务)
Fair调度类:应用于普通任务,均由CFS调度器管理
💡我们之前谈到的deadline以及realtime也是由于对应的调度器来管理?
❓调度器如何同时兼并多种调度策略
- SCHED_NORMAL:普通任务使用的调度策略;
- SCHED_BATCH:后台任务的调度策略,不和终端进行交互,因此在不影响其他需要交互的任务,可以适当降低它的优先级。
完全公平调度
Linux 里面,实现了一个基于 CFS 的调度算法,也就是完全公平调度(Completely Fair Scheduling)。
他的思想是给每个task一个对应的时间(vruntime(这是一个假设你task运行的时间,随着这个task不断被选中运行,他的vruntime也会不断增加,(到时候我们选会优先选择时间更少的,这才公平嘛))),当然即使是面向普通任务,不同优先级的task的分配时间也各有不同(别忘了,我们是分成实时任务与普通任务两大类,他们之间的优先级多了去了)
vruntime的计算公式为:
vruntime+=实际运行时间*优先级(与nice值有关)
这很符合我们的原意,毕竟我们是根据vruntime时间越少的越优先嘛
运行队列
每个核中的都有着对应的运行队列
运行队列中包括三个调用类对应的运行队列
cfs_rq是用红黑树来描述的,按vruntime大小来排序,最左侧的叶子节点,就是下次会被调用的任务
在运行队列选择哪个任务来执行中,仍然会先考虑调用类的优先级:dl>rt>fair,之后再去由其中的内部运行队列接着决定,正是由此才使得"实时任务优于普通任务"
调整优先级
如果调整普通任务优先级的话
启动任务,没有指定优先级,默认为普通任务
如果想在普通任务这个大类中调整局部优先级的话,
那就得用nice值了,nice的设置范围为:-20~19,这是一个偏移量(或者如小林哥说的修正数值),它与优先级(priority)的关系是这样的:priority(new) = priority(old) + nice。
至于取值范围正是限制在调整完依旧是普通任务:
并且这指明了一个点:最终导致运行时间改变的还是优先级
具体看图则了解:
启动任务的时候,指定 nice 的值,比如将 mysqld 以 -3 优先级:
修改已经运行中的任务的优先级,使用 renice
来调整 nice 值:
如果想把普通任务调整成实时任务的话
-f代表fifo
如果-rr则代表rr
参考
小林的博客