Linux线程调度实验
1.获取线程属性
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdlib.h> #include <errno.h> #define _GNU_SOURCE #define handle_error_en(en, msg) \ do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) static void display_pthread_attr(pthread_attr_t *attr, char *prefix){ int s, i; size_t v; void *stkaddr; struct sched_param sp; s = pthread_attr_getdetachstate(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getdetachstate"); printf("%sDetach state = %s\n", prefix, (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" : (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" : "???"); s = pthread_attr_getscope(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getscope"); printf("%sScope = %s\n", prefix, (i == PTHREAD_SCOPE_SYSTEM) ? "PTHREAD_SCOPE_SYSTEM" : (i == PTHREAD_SCOPE_PROCESS) ? "PTHREAD_SCOPE_PROCESS" : "???"); s = pthread_attr_getinheritsched(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getinheritsched"); printf("%sInherit scheduler = %s\n", prefix, (i == PTHREAD_INHERIT_SCHED) ? "PTHREAD_INHERIT_SCHED" : (i == PTHREAD_EXPLICIT_SCHED) ? "PTHREAD_EXPLICIT_SCHED" : "???"); s = pthread_attr_getschedpolicy(attr, &i); if (s != 0) handle_error_en(s, "pthread_attr_getschedpolicy"); printf("%sScheduling policy = %s\n", prefix, (i == SCHED_OTHER) ? "SCHED_OTHER" : (i == SCHED_FIFO) ? "SCHED_FIFO" : (i == SCHED_RR) ? "SCHED_RR" : "???"); s = pthread_attr_getschedparam(attr, &sp); if (s != 0) handle_error_en(s, "pthread_attr_getschedparam"); printf("%sScheduling priority = %d\n", prefix, sp.sched_priority); s = pthread_attr_getguardsize(attr, &v); if (s != 0) handle_error_en(s, "pthread_attr_getguardsize"); printf("%sGuard size = %zu bytes\n", prefix, v); s = pthread_attr_getstack(attr, &stkaddr, &v); if (s != 0) handle_error_en(s, "pthread_attr_getstack"); printf("%sStack address = %p\n", prefix, stkaddr); printf("%sStack size = 0x%zx bytes\n", prefix, v); } void* computing(void* arg){ int s; pthread_attr_t gattr; s = pthread_getattr_np(pthread_self(), &gattr); if (s != 0) handle_error_en(s, "pthread_getattr_np"); printf("Thread attributes:\n"); display_pthread_attr(&gattr, "\t"); pause(); pthread_exit(0); } int main(){ pthread_t tid; pthread_attr_t attr; pthread_attr_init(&attr); // 线程创建函数 pthread_create(&tid, &attr, computing, NULL); // 等待指定的线程结束 pthread_join(tid,NULL); return 0; }
这个库函数报错不用管
我们可以看到当前进程:
datach state:这个进程是一个joinable,也就是一个可进入等待状态的进程
scope:有两种状态
这两个的区别
一个是系统范围,一个是进程范围,如果我有多个线程,那么他们的竞争区间是在自己的进程内,还是整个系统的进程内
系统范围竞争
进程内竞争
我们linux系统的线程是系统范围竞争,我们前面学了用户模型和系统模型1对1模型,其实linux就是1
inherit schedule:调度器是谁
这里可以看出是继承调度,调度器的参数和属性会被这个进程所继承。
执行策略是:SCHED_OTHER
下面两个fifo和RR一个是先进先出,一个是时间片
Linux线程调度策略总共有两种:
- Normal Scheduling(正常调度):总共有三种,分别为SCHED_OTHER,SCHED_IDLE,SCHED_BATCH, 它的优先级数值priority_value需要设置成0,但这里并不一定意味着这个进程优先级很高,因为这个0是默认值。
- Real_time Schedulig(实时调度):总共有两种:一种是SCHED_FIFO(先来先服务),SCHED_RR(时间片轮转),实时调度的进程总是比正常调度的进程优先级要高,它的优先级数值priority_value∈[1,99],这里和前面我们学的系统优先级不同,1是低优先级,99是高优先级
实时调度需要延迟非常低才可以实现,所以现在用户模式的进程基本都是一般都是正常调度的。
这里SCHED_OTHER是RR,现在默认的状态是这个。
linux中优先级越低,进程或线程的优先级越高
PR值越高优先级越低
一般nice值默认为0
SCHED_IDLE:一般是周期性计划任务,清理磁盘等,优先级不是很高。
可以使用 ps -eLl来查看当前线程
LWP, light weight process 这里是4544和4545是用户模式产生的线程id
NLWP,Number of Light-Weight Processes
我们再用top看下
PR值为rt(实时进程)、负数(实时进程)、0(优先级极高),默认值20。
NI(nice)值:默认为0
top -p 4544
单看下当前进程的调度策略
看一个real time的进程
nice值仅在用户模式下有用
Real_time Scheduling【包含FIFO和RR】:
它的PR值计算公式为:PR = -1 - priority_value
所以PR∈[-100,-2]
可以看出左轴从-1开始都是rt的进程
所以我们可以通过PR值来判断一个进程/线程是Noraml Thread还是Real-time thread,是正数就
是Noraml Thread,是负数就是Real-time thread。
PR值=100
-r转化成RR策略的rt进程
-f转化成Fifo策略的rt进程
value 1~99 , 99代表优先级最高
我们把我们执行的这个进程转为fifo策略的real time 进程
sudo chrt -f -p 11 4544
-1-value