Linux实时调度策略(SCHED_RR)和CFS(SCHED_OTHER)之间的区别

本文对比了Linux系统中SCHED_RR实时调度策略和CFS(SCHED_OTHER)的区别。在满负荷运行时,CFS调度策略保持系统响应,而SCHED_RR导致严重卡顿。通过调整实时线程占用处理器的比例,可以缓解实时调度策略的影响。nice和renice命令用于调整进程优先级和友善度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文试图从直观角度,说明SCHED_RR调度策略和SCHED_OTHER调度策略之间的区别。

在Linux上,SCHED_OTHER和SCHED_NORMAL的意思相同,它们都是指的CFS调度策略,只不过,在内核中,CFS定义为SCHED_NORMAL,在用户态,CFS定义为SCHED_OTHER.

可参照内核头文件和musl libc头文件:

测试代码如下:

#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>

void *child_thread(void *arg)
{
	int policy = 0;
	int max_priority = 0,min_priority = 0;
	struct sched_param param;
	pthread_attr_t attr;
	struct sched_param sp;
	bzero((void*)&sp, sizeof(sp));
	 
	pthread_attr_init(&attr);
	pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);
	pthread_attr_getinheritsched(&attr,&policy);

	if(policy == PTHREAD_EXPLICIT_SCHED){
		printf("Inheritsched:PTHREAD_EXPLICIT_SCHED\n");
	}

	if(policy == PTHREAD_INHERIT_SCHED){
		printf("Inheritsched:PTHREAD_INHERIT_SCHED\n");
	}
	 
	//pthread_attr_setschedpolicy(&attr,SCHED_RR);
	pthread_attr_setschedpolicy(&attr,SCHED_OTHER);
	pthread_attr_getschedpolicy(&attr,&policy);

	if(policy == SCHED_FIFO){
		printf("Schedpolicy:SCHED_FIFO\n");
	}
	if(policy == SCHED_RR){
		printf("Schedpolicy:SCHED_RR\n");
	}
	if(policy == SCHED_OTHER){
		printf("Schedpolicy:SCHED_OTHER\n");
	}

	max_priority = sched_get_priority_max(policy);
	min_priority = sched_get_priority_min(policy);
	printf("Maxpriority:%u\n",max_priority);
	printf("Minpriority:%u\n",min_priority);
	 
	param.sched_priority = max_priority;
	pthread_attr_setschedparam(&attr,&param);

	sp.sched_priority = 1;
	// Actually set the sched params for the current thread.
	if (0 == pthread_setschedparam(pthread_self(), policy, &sp)) {
		printf("IO Thread #%ld using high-priority scheduler!", pthread_self());
	}

	printf("sched_priority:%u\n",param.sched_priority);
	while(1);
	pthread_attr_destroy(&attr);
}
 
int main(int argc,char *argv[ ])
{
	pthread_t child_thread_id; 
	pthread_create(&child_thread_id,NULL,child_thread,NULL);
	pthread_join(child_thread_id,NULL);

	return 0;
} 

代码执行流前首先设置了调度策略为SCHED_OTHER, pthread_attr_setschedpolicy(&attr,SCHED_OTHER);之后执行while(1);循环占住CPU。

执行前通过nice命令设置线程的优先级,由于PC处理器是四核,所以执行四次,让每个CPU上都执行满载,如下图所示:

caozilong@caozilong-
进程调度队列是如何组织的: 在 Linux 内核中,进程调度队列是由多个就绪队列(runqueue)组成的。每个 CPU 都有一个就绪队列,用于保存可以被调度的进程。就绪队列是一个双向链表,每个链表节点对应一个进程。就绪队列使用了一些优化技巧,例如旋转数组(rotating bitmap)红黑树(red-black tree),以提高调度效率。 三种调度类型(SCHED_FIFO, SCHED_RR, SCHED_OTHER)的实现过程: Linux 内核中支持三种调度类型: - SCHED_FIFO:先进先出调度策略,进程一旦被调度,将一直占用 CPU 直到自愿放弃或者被其他进程抢占。 - SCHED_RR:时间片轮转调度策略,进程被分配固定的时间片,当时间片用完或者进程主动放弃 CPU 时,进程就会被放回到就绪队列中,等待下一次调度。 - SCHED_OTHERCFS(Completely Fair Scheduler)调度策略,基于进程的虚拟运行时间(vruntime)来决定进程的优先级。优先级较高的进程被调度的机会更高。 在 Linux 内核中,这三种调度类型的实现都是基于调度类(sched_class)的概念。每个调度类都包含了一组函数指针,用于实现进程调度相关的操作。不同的调度类实现不同的调度策略。 优先级是如何定义动态变化的: 在 Linux 内核中,进程的优先级是一个动态变化的值,取值范围为 -20 到 19。优先级较高的进程会更容易被调度。进程的优先级由调度类的实现决定,不同的调度类可以有不同的优先级计算方式。 时间片的赋值?它与优先级的关系? 在 Linux 内核中,时间片的赋值与优先级有关。时间片的大小由进程的优先级决定,优先级越高的进程分配的时间片越长。具体来说,时间片的大小可以通过以下公式计算: time_slice = 100 * 2 ^ (MAX_PRIO - prio) 其中,MAX_PRIO 是进程优先级的最大值,prio 是进程的优先级。时间片的单位是 jiffies(时钟滴答数),具体的大小可以通过 kernel/sched/core.c 中的 time_slice() 函数计算。 重点分析内核数据结构 task_struct(在 include/linux/sched.h 中)调度函数 schedule()(在 kernel/sched.c 中): task_struct 结构体是 Linux 内核中描述进程的主要数据结构,其中包含了进程的各种信息,包括进程 ID、优先级、状态等等。task_struct 结构体比较庞大,其中包含了多个子结构体,例如 thread_info、mm_struct、fs_struct 等等。 schedule() 函数是 Linux 内核中实现进程调度的核心函数,它由内核定时器触发,用于从就绪队列中选择下一个需要运行的进程。schedule() 函数首先会检查当前 CPU 上是否有正在运行的进程,如果有,则不进行调度;否则,它会从就绪队列中选择下一个进程,并将其调度到 CPU 上运行。如果就绪队列为空,则 schedule() 函数会将当前 CPU 切换到 idle 进程上,以节省 CPU 资源。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值