linux线程调度策略和优先级使用

1.调度策略和优先级

1.1.调度策略

sched.h文件中定义了几种调度策略

/* Scheduling algorithms.  */
#define SCHED_OTHER		0
#define SCHED_FIFO		1
#define SCHED_RR		2 

SCHED_OTHER:非实时调度,分时调度。通过pthread_create创建,但属性参数传递NULL创建的线程默认以SCHED_OTHER方式创建。使用CFS调度器(Linux2.6.23引入作为默认用户进程分时调度器),时间片是动态的,使用红黑树取代了传统运行队列来管理任务,使CPU消耗比较小的进程相比CPU消耗比较高的进程更容易找到,提供了交互和I/O消耗性负载的性能。

SCHED_FIFO :实时调度,即操作系统教材中描述的FCFS,先到先服务。需要明确指定。当一个任务就绪时,添加到就绪队列的尾部,当CPU空闲时,首先分配给就绪队列的头部的任务,直到运行任务完成(除非有若干特别的情况发生,如任务主动让出cpu、发生阻塞进入等待队列、更高优先级的任务出现(多核CPU场景))。一般策略代码简单,但平均等待时间比较长,一个任务可能保持CPU时间过长。

SCHED_RR :实时调度,基于时间片轮转,即操作系统教材中描述的Round robin。需要明确指定。类似FCFS,使用时间片,CPU运行了就绪队列头部的任务一个时间片的时长后,将此任务放到就绪队列的尾部,调度就绪队列头部的新任务就行运行,直到时间片结束,按此循环。其中新产生的任务被添加到就绪队列的尾部。一般这种调度策略平均等待时间比较长。

使用建议
1、长时间运行的任务所在线程创建时,不能设置为SCHED_FIFO调度策略模式,否则会阻塞其他优先级比较低的周期性实时的短任务。(经验教训,OTA升级过程所在的线程所在线程错误地以SCHED_FIFO创建,每次升级时导致了各种奇怪的问题,如心跳检测线程没反应了,导致不停重启应用组件。同时表现CPU占用95%以上。)

1.2.混合策略

系统中既有普通分时调度SCHED_OTHER,又有SCHED_FIFO或SCHED_RR调度策略时,进行了权重分配。如

Ubuntu18.04版本PC平台及linux 3.18.20 ARM平台测试,cd 到/proc/sys/kernel目录下操作

$ cat sched_rt_runtime_us
950000
$ cat sched_rt_period_us
1000000

表示实时任务运行周期是1秒,运行周期内最多允许0.95秒,剩余时间为普通进程的运行时间。

1.3.优先级

Linux为实时进程设置100个优先级:0~99,其中0为最高,99为最低

1.4.设置线程调度策略优先级步骤

1.4.1pthread_attr_init初始化线程属性结构体

int pthread_attr_init (pthread_attr_t *__attr) __THROW __nonnull ((1));

内核源代码中注释如下:

Initialize thread attribute *ATTR with default attributes
   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,
    no user-provided stack). 

表示:使用默认参数初始化线程属性 ,可分离状态为 PTHREAD_JOINABLE,调度策略为SCHED_OTHER,不使用用户栈

1.4.2.pthread_attr_setschedpolicy 设置调度策略

int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)
     __THROW __nonnull ((1));

1.4.3.pthread_attr_setschedparam设置优先级

scheparam.__sched_priority  = (优先级数值);
pthread_attr_setschedparam(&attr,&scheparam);

1.4.4.pthread_attr_setinheritsched设定线程调度策略的继承属性

int pthread_attr_setinheritsched (pthread_attr_t *__attr,
					 int __inherit)
     __THROW __nonnull ((1));

1.4.5.pthread_attr_destroy

int pthread_attr_destroy (pthread_attr_t *__attr) __THROW __nonnull ((1));

如果pthread_attr_init中动态创建了内存空间,则这里会释放。

1.5.查询运行线程调度策略和优先级

###1.5.1.使用函数

int pthread_getschedparam (pthread_t __target_thread,int *__restrict __policy,struct sched_param *__restrict __param)  __THROW __nonnull ((2, 3));

###1.5.2.打印策略和优先级函数封装

void printCurrentThreadPriority()
{
	struct sched_param sch;
	int policy = -1;
	pthread_t pt;
	int res =-1;
	pt =  pthread_self();
	res = pthread_getschedparam(pt , &policy, &sch) ;
	if(res!=0)
	{
		printf("[Thread]pthread_getschedparam error,res=%d\n",res);
	}
	printf("[Thread]:pid=%d,ppid=%d,uid=%d,euid=%d,gid=%d,egid=%d ,threadid=0x%lx,priority=%d,policy=%d(0:OTHER,1:FIFO,2:RR)\n"
			, getpid(),getppid(),getuid(),geteuid(),getgid(),getegid(),(unsigned long) pthread_self(),sch.sched_priority,policy);

}

###1.5.3.插入线程进行打印
进程的主线程main中进行打印:

[Thread]:pid=24416,ppid=1,uid=0,euid=0,gid=0,egid=0 ,threadid=0xb6eed000,priority=0,policy=0(0:OTHER,1:FIFO,2:RR)

通过pthread_create创建,但属性参数传递NULL创建的线程中打印:

[Thread]:pid=21790,ppid=1,uid=0,euid=0,gid=0,egid=0 ,threadid=0xb64ff450,priority=0,policy=0(0:OTHER,1:FIFO,2:RR)

通过pthread_create创建,但属性参数传递调度策略为SCHED_FIFO,优先级为65的线程中打印:

[Thread]:pid=24416,ppid=1,uid=0,euid=0,gid=0,egid=0 ,threadid=0xb6e7a450,priority=65,policy=1(0:OTHER,1:FIFO,2:RR)

备注:运行平台linux 3.18.20,arm单处理器

2.参考资料

UNIX环境高级编程,第3版, [Advanced Programming in the UNIX Environment, Third Edition]
操作系统概念,第6版,西尔伯查茨著 郑扣根译 高等教育出版社
性能之巅,【美】格雷格(Brendan Gregg,B.) ,2015年8月 ,电子工业出版社
https://blog.csdn.net/u013007900/article/details/49965261/ https://blog.csdn.net/u012007928/article/details/40144089

你可能感兴趣的:(linux,进程/线程)