疑问

两个线程分别有不同的调度策略,一个SCHED_FIFO,一个SCHED_OTHER,按照之前的理解,SCHED_FIFO实时线程一定会占用CPU一直运行,导致SCHED_OTHER的普通线程得不到CPU,事实是这样么?

验证

写了一小段代码,一个是验证SCHED_FIFO的高优先级线程会不会抢占低优先级的线程,在不主动放弃的情况下一直运行,一个是测试普通优先级的线程会不会得到CPU时间;

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
#include <sched.h> long long a = ;
long long b = ; int attach_cpu(int cpu_index)
{
int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
if (cpu_index < || cpu_index >= cpu_num)
{
printf("cpu index ERROR!\n");
return -;
} cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(cpu_index, &mask); if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < )
{
printf("set affinity np ERROR!\n");
return -;
} return ;
} void *thread1(void *param)
{
attach_cpu(); long long i;
for (i = ; i < ; i++)
{
a++;
}
} void *thread2(void *param)
{
attach_cpu(); long long i;
for (i = ; i < ; i++)
{
b++;
}
} int main()
{
pthread_t t1;
pthread_t t2; int policy;
struct sched_param param; if (pthread_create(&t1, NULL, thread1, NULL) < )
{
printf("create t1 failed!\n");
return -;
} param.sched_priority = ;
policy = SCHED_FIFO;
pthread_setschedparam(t1, policy, &param); if (pthread_create(&t2, NULL, thread2, NULL) < )
{
printf("create t2 failed!\n");
return -;
} param.sched_priority = ;
policy = SCHED_FIFO;
pthread_setschedparam(t2, policy, &param); while ()
{
printf("a=%lld, b=%lld\n", a, b);
sleep();
} pthread_join(t1, NULL);
pthread_join(t2, NULL); return ;
}

通过运行结果来看:

1. SCHED_FIFO的高优先级线程会抢占低优先级线程;

2.SCHED_FIFO的高优先级线程一旦占用CPU并不主动放弃CPU的情况下将一直占用,此时低优先级线程得不到CPU时间;

3.主线程为SCHED_OTHER普通线程,得到了CPU时间,能够打印出信息;

原理

对于上述现象在manpage中已经有了很好的描述,以下摘录一些;前面的疑问在下面的限制实时线程的CPU使用时间部分;

调度策略

系统中的每个线程都关联了一个调度策略和优先级,调度器正是根据调度策略和优先级进行线程调度的,从而决定哪个线程将在下一个调度中得到CPU时间;

对于普通调度策略(SCHED_OTHER, SCHED_IDLE, SCHED_BATCH),优先级是没有作用的,实际上必须是0,这样实时测量线程可以马上抢占普通线程;

对于实时调度策略(SCHED_FIFO, SCHED_RR),优先级需要设置为1(最小)-99(最大)中的某个值;

调度器为每个优先级维护了一个待调度线程的列表,当需要进行调度时,调度器访问最高优先级的非空的列表,然后从列表头选择一个线程调度运行;

线程的调度策略决定了一个可调度线程应该放在哪个列表的哪个位置;

所有的调度都是支持抢占的,如果有高优先级的线程准备好运行了,那么它将抢占当前运行的线程,这使得当前线程被重新加入到等待调度的链表中;调度策略决定了在同一个优先级列表中的可调度线程的顺序;

SCHED_FIFO:先进先出调度

SCHED_FIFO线程的优先级必须大于0,当它运行时,一定会抢占正在运行的普通策略的线程(SCHED_OTHER, SCHED_IDLE, SCHED_BATCH);SCHED_FIFO策略是没有时间片的算法,需要遵循以下规则:

1)如果一个SCHED_FIFO线程被高优先级线程抢占了,那么它将会被添加到该优先级等待列表的首部,以便当所有高优先级的线程阻塞的时候得到继续运行;

2)当一个阻塞的SCHED_FIFO线程变为可运行时,它将被加入到同优先级列表的尾部;

3)如果通过系统调用改变线程的优先级,则根据不同情况有不同的处理方式:

a)如果优先级提高了,那么线程会被添加到所对应新优先级的尾部,因此,这个线程有可能会抢占当前运行的同优先级的线程;

b)如果优先级没变,那么线程在列表中的位置不变;

c)如果优先级降低了,那么它将被加入到新优先级列表的首部;

根据POSIX.1-2008规定,除了使用pthread_setschedprio(3)以外,通过使用其他方式改变策略或者优先级会使得线程加入到对应优先级列表的尾部;

4)如果线程调用了sched_yield(2),那么它将被加入到列表的尾部;

SCHED_FIFO会一直运行,直到它被IO请求阻塞,或者被更高优先级的线程抢占,亦或者调用了sched_yield();

SCHED_RR:轮转调度

SCHED_RR是SCHED_FIFO的简单增强,除了对于线程占用的时间总量之外,对于SCHED_FIFO适用的规则对于SCHED_RR同样适用;如果SCHED_RR线程的运行时间大于等于时间总量,那么它将被加入到对应优先级列表的尾部;如果SCHED_RR线程被抢占了,当它继续运行时它只运行剩余的时间量;时间总量可以通过sched_rr_get_interval()函数获取;

SCHED_OTHER:默认Linux时间共享调度

SCHED_OTHER只能用于优先级为0的线程,SCHED_OTHER策略是所有不需要实时调度线程的统一标准策略;调度器通过动态优先级来决定调用哪个SCHED_OTHER线程,动态优先级是基于nice值的,nice值随着等待运行但是未被调度执行的时间总量的增长而增加;这样的机制保证了所有SCHED_OTHER线程调度的公平性;

限制实时线程的CPU使用时间

SCHED_FIFO, SCHED_RR的线程如果内部是一个非阻塞的死循环,那么它将一直占用CPU,使得其它线程没有机会运行;

在2.6.25以后出现了限制实时线程运行时间的新方式,可以使用RLIMIT_RTTIME来限制实时线程的CPU占用时间;Linux也提供了两个proc文件,用于控制为非实时线程运行预留CPU时间;

/proc/sys/kernel/sched_rt_period_us

这个文件中的数值指定了总CPU(100%)时间的宽度值,默认值是1,000,000;

/proc/sys/kernel/sched_rt_runtime_us

这个文件中的数值指定了实时线程可以运行的CPU时间宽度,如果设置为-1,则认为不给非实时线程预留任何运行时间,默认值是950,000,因为第一个文件的总量是1,000,000,也就是说默认配置为非实时线程预留了5%的CPU时间;

manpage连接:http://man7.org/linux/man-pages/man7/sched.7.html

SCHED_FIFO与SCHED_OTHER调度机制的更多相关文章

  1. (笔记)Linux内核学习(十一)之I/O层和I/O调度机制

    一 块I/O基本概念 字符设备:按照字符流的方式被有序访问的设备.如串口.键盘等. 块设备:系统中不能随机(不需要按顺序)访问固定大小的数据片(chunk 块)的设备. 如:硬盘.软盘.CD-ROM驱 ...

  2. quartz集群调度机制调研及源码分析---转载

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  3. 定时组件quartz系列<三>quartz调度机制调研及源码分析

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  4. (1)quartz集群调度机制调研及源码分析---转载

    quartz2.2.1集群调度机制调研及源码分析 原文地址:http://demo.netfoucs.com/gklifg/article/details/27090179 引言quartz集群架构调 ...

  5. quartz群调查调度机制和源代码分析

    pageId=85056282#quartz集群调度机制调研及源代码分析-quartz2.2.1集群调度机制调研及源代码分析" style="color:rgb(59,115,17 ...

  6. Linux进程组调度机制分析【转】

    转自:http://oenhan.com/task-group-sched 又碰到一个神奇的进程调度问题,在系统重启过程中,发现系统挂住了,过了30s后才重新复位,真正系统复位的原因是硬件看门狗重启的 ...

  7. [k8s]k8s的控制层kubelet+docker配合调度机制(k8架构)

    意外停掉一台node的kubelet,发现调度有问题,研究了下调度的细节 k8s架构 控制层- kubelet(配合节点docker工作) 数据层- kube-proxy 逻辑图: object 参考 ...

  8. Golang 的 协程调度机制 与 GOMAXPROCS 性能调优

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  9. [转]golang的goroutine调度机制

    golang的goroutine调度机制 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 一直对goroutine的调度机制很好奇最近在看雨痕的golang源码分析基于go ...

随机推荐

  1. Linux查找文件之Find命令

    Linux系统文件中常用属性包括以下内容:名称,大小,权限,属主,属组,修改时间,访问时间等.在庞大的Linux系统中查询文件,需要借助查找工具来实现,依此可以查询相同或指定属性的文件,本文所讲的查询 ...

  2. element-ui DatePicker 日期选择器 让结束日期大于开始日期

    element-ui  DatePicker 日期选择器 <el-date-picker v-model="addForm.startDate" type="dat ...

  3. visualSVN server 安装成功,但是无法连接,url打不开

    转自:https://www.oschina.net/question/878142_91825 点击开始–>程序->VisualSVN–>VisuaSVN Server Manag ...

  4. LTS秘钥协商算法分析

    1.根据RCF文档说法 在1-RTT中有两种密钥协商算法(1-RTT ECDHE和 1-RTT PSK  )和4中0-RTT密钥协商方式(0-RTT PSK, 0-RTT ECDH ,0-RTT EC ...

  5. Java--8--新特性--Stream API

    Stream API 提供了一种高效且易于使用的处理数据的方式,(java.util.stream.*) 他可以对数组,集合等做一些操作,最终产生一个新的流,原数据是不会发生改变的. “集合”讲的是数 ...

  6. Nginx练习练习玩玩

    Date:2019-11-9 读前思考: 对于NGINX,一般会问什么? 面试官会从哪方面入手? 面试官到底想考察什么? 你做好准备了吗? 如果对于初学者,往往可以通过面试题来提升对某一个技术的了解和 ...

  7. JDBC_通过DriverManager获得数据库连接

    package day_18; import org.junit.Test; import java.io.InputStream; import java.sql.*; import java.sq ...

  8. SQL进阶17-变量的声明/使用(输出)--全局变量/会话变量--用户变量/局部变量

    /*进阶17 变量 系统变量: 全局变量: 会话变量: 自定义变量: 用户变量: 局部变量: */ /* #一: 系统变量 #说明: 变量由系统提供,不是用户定义的,属于服务器层面 #使用的语法 #1 ...

  9. LOJ-1308-Ant network(蚂蚁的网络)-求割点分隔开的子图个数及乘积

    网上的题解大都模糊,我可能写的也比较模糊吧,讲究看看. 大致题意: 原图没有一个割点时,特殊考虑,至少ans1=2个通风井,方案数n*(n-1)/2; 原图上有多个割点时,每个(由割点限制成几部分的) ...

  10. Select count(*)和Count(1)的区别和执行方式

    在SQL Server中Count(*)或者Count(1)或者Count([列])或许是最常用的聚合函数.很多人其实对这三者之间是区分不清的.本文会阐述这三者的作用,关系以及背后的原理. 往常我经常 ...