在了解sleep(0)和sched_yield之前先让我们看看linux是怎么调度的(这里只讲CFS)
1.CFS
CFS不会根据优先级分配一个不变的运行时间,比如说分配5ms这样的,它是一个分配占用处理器比例的一个分配算法。CFS的做法是允许每个进程运行一段时间,循环轮转,选择运行最少的进程(通过vruntime来判断,下面可以看到vruntime是怎么计算的)作为下一个运行进程,而不再采用分配给每个进程时间片的做法了。CFS在所有可运行进程总数基础上计算出一个进程应该运行多久,而不是依靠nice值来计算时间片。nice值在CFS中被作为进程获得的处理器运行比的权重:越高的nice值(越低的优先级)进程获得更低的处理器使用权重,这是相对默认nice值进程的进程而言的。相反,更低的nice值(越高的优先级)的进程获得更高的处理器使用权重。
CFS调度器的一个调度周期值是固定的,由sysctl_sched_latency变量保存。
一个进程在一个调度周期中的运行时间为:
分配给进程的运行时间 = 调度周期*进程权重/所有进程权重之和
从上面可以看到一个进程的优先级越高(权重越大,分到的运行时间越多)。
一个进程的实际运行时间和虚拟运行时间之间的关系为
vruntime = 实际运行时间*NICE_0_LOAD / 进程权重
= 实际运行时间*1024 / 进程权重
从上面可以看到,进程的权重越大,vruntime增长的越慢。比如说,进程的权重为1024的进程,运行时间为1时,vruntime为1。再看看进程权重为512的进程,运行时间为0.5时,vruntime就为1了。(在这里可以理解CFS根据vruntime来调度进程运行了)
一个进程在一个调度周期内分配到的虚拟运行时间大小为:
vruntime = 进程在一个调度周期内的实际运行时间*1024 / 进程权重
= (调度周期 * 进程权重 / 所有进程总权重) * 1024 / 进程权重
= 调度周期*1024 / 所有进程总权重
可以看到一个进程在一个调度周期内分配到的vruntime值大小都是一样的
上面的分析是引用的https://blog.csdn.net/liuxiaowu19911121/article/details/47070111
2.三个队列:运行队列,过期队列,等待队列
1.等待队列:休眠(或者阻塞)的进程放在等待队列里面,进程的状态为TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE
2.运行队列:这些进程还没有用完时间片,因此允许它们运行。
3.过期队列:时间片运行完的进程放在这个队列,这里面的进程不能被调度运行,除非所有的进程都运行完了自己的时间片。
3.sleep(n),sleep(0),sched_yield
sleep(n):把进程状态设为TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE,然后在放入等待队列中。当睡眠的时间足够了之后再放入运行队列中(注意有可能被唤醒之后就能执行也有可能过一段时间才能执行)
sleep(0):让CPU在根据调度程序去调度,如果存在vruntime比它小的就让那个进程运行,如果不存在就自己继续运行
sched_yield:sched_yield把自己放入过期队列中,所以需要等所有的进程过期之后才有可能运行