1. 调度
1.1 优先级
- 静态优先级
优先级值越大优先级越高
普通任务优先级0,普通任务没有办法和系统任务参与系统资源的竞争
普通任务之间用动态优先级竞争系统资源 - 动态优先级
1.2 静态优先级线程调度策略
-
SCHED_OTHER
分时调度、设置虚拟时钟计时,
每个进程有一个vruntime,得到运行时,vruntime就会增加,每次调度会优先选vruntime最小的
不同优先级的进程 vruntime 增长速度不同 -
SCHED_FIFO
当一条线程采用该调度策略则会一直运行,直到它被更高优先级的线程抢占或者主动放弃CPU,才会交出控制权。当线程完成后,内核会去寻找处于就绪状态相同优先级的线程,如果不存在,则寻找低优先级线程。该调度策略实现了数据的互斥,在线程运行的时间内其他相同优先级线程无法进行资源抢占。 -
SCHED_RR
时间片轮转,是实时调度策略。
消耗完成时间片后、高优先级抢占、主动放弃cpu,会主动交出控制权
使用默认属性创建的线程,默认调度策略是SCHED_OTHER
切换调度策略的函数是:
pthread_attr_setschedpolicy()
注意:如果用户准备设置线程的调度属性,则应该先调用pthread_attr_setinheritsched()函数,并设置线程属性对象attr的继承调度属性为PTHREAD_EXPLICIT_SCHED。
练习:创建一条指定属性的线程,要求线程的调度策略为先到先服务策略,提示:创建属性对象 --> 初始化属性对象 --> 设置属性对象的继承调度属性(不继承) --> 设置调度策略!
如何设置线程的静态优先级?
pthread_attr_setschedparam()
如果调度策略是 sched_other,优先级必须设置为0,表示普通任务
如果是sched_fifo或者sched_rr
则可以设置为1-99,此时运行必须使用root权限
练习:设计一个程序,要求在程序中创建一条线程,线程的属性由用户指定,要求线程的调度策略为SCHED_OTHER,并且线程的静态优先级设置为0。
动态优先级
动态优先级指的是当多个普通任务并发运行时,系统会根据其实际运行的表现来动态地调整他们的nice值,任务的表示如下:
A. 睡眠时间越多,放着系统资源不用,系统就倾向于判定其为IO消耗性的任务,会逐步提高其优先级
B. 睡眠时间越少,拼命抢占系统资源,系统就倾向于判定其为CPU消耗性任务,会逐步降低其优先级
Linux系统中线程的nice值越高,则优先级越低,而nice值越低,反而优先级越高
用户可以修改普通任务的动态优先级,实际上就是修改普通任务的nice值即可,Linux系统提供了一个名字叫做nice()的函数接口
nice值的范围是-20 ~ 19,其中-20是最高优先级,19是最低优先级,所以nice值越小,则优先级越高
进程的nice值默认为0,如果要降低nice值(即想要提高优先级),那么启动程序时必须加sudo,获得管理员的权限才能启动
练习:编写一个多线程程序,要求创建两条相同静态优先级但不同动态优先级的的线程,一个线程的任务是在死循环输出数字,另一个线程的任务是在死循环输出字母,观察其运行效果。提示:需要确保Linux系统的处理器数量和内核数量为1
2. 线程响应
向进程发送信号时,需要指定一个线程对信号响应,其他线程则屏蔽信号
pthread_kill()
可以向指定线程发信号
pthread_sigqueue()
可以发额外的数据
pthread_sigmask()
和sigprocmask()
可用于屏蔽信号
练习:设计一个程序,要求程序中有3条子线程,子线程A接收到SIGINT信号时就输出自身的线程ID,子线程B和子线程C则屏蔽该信号,运行程序并观察效果。