Linux的进程管理之RT调度器—5

1.理论介绍

RT调度器是所有实时进程所依赖的调度器,其优先级为0-99,常常用于嵌入式设备;
此调度器实现了SCHED_RR与SCHED_FIFO策略,最主要的区别是SCHED_RR是有时间片的概念,而SCHED_FIFO属于一直执行的状态,直到执行此线程主动退出,或者被高优先级的线程抢占。
其中cpu上的队列通过rt_rq指向其哈希表,调度实体sched_rt_entity通过哈希表进行组织;
在这里插入图片描述

2.RT调度器的实现

所有的调度器都是通过函数指针进行实现,各自进行初始化,c中函数指针的使用使得c可以模仿出面向对象的接口,而实际的项目开发中也多有使用,在学习调度的同时也可以多加体会。

static const struct sched_class rt_sched_class = {
	.next			        = &fair_sched_class,
	.enqueue_task		    = enqueue_task_rt,
	.dequeue_task		    = dequeue_task_rt,
	.yield_task		        = yield_task_rt,
	.check_preempt_curr	    = check_preempt_curr_rt,
	.pick_next_task		    = pick_next_task_rt,
	.put_prev_task		    = put_prev_task_rt,
#ifdef CONFIG_SMP
	.select_task_rq		    = select_task_rq_rt,
	.set_cpus_allowed       = set_cpus_allowed_rt,
	.rq_online              = rq_online_rt,
	.rq_offline             = rq_offline_rt,
	.pre_schedule		    = pre_schedule_rt,
	.post_schedule		    = post_schedule_rt,
	.task_woken		        = task_woken_rt,
	.switched_from		    = switched_from_rt,
#endif
	.set_curr_task          = set_curr_task_rt,
	.task_tick		        = task_tick_rt,
	.get_rr_interval	    = get_rr_interval_rt,
	.prio_changed		    = prio_changed_rt,
	.switched_to		    = switched_to_rt,
};

3.pick_next_task

其作用是找到下一个调度的线程,RT调度器中实际的函数为pick_next_task_rt,我们不过多在乎细节,梳理主要的流程:
在这里插入图片描述

其中主要有两个函数,通过pick_next_rt_entity找到下一个调度实体,然后通过rt_task_of找到对应的线程信息;
pick_next_rt_entity函数:
sched_find_first_bit从0->99进行扫描,找到优先级最高的实体链表头;
list_entry函数即找到此链表上的第一个节点;至此找到了对应的调度实体sched_rt_entity;
rt_task_of函数:
通过调度container_of宏找到对应的线程结构体task_struct;

3.1.container_of宏

在寻找下一个线程pick_next_task_rt函数的时候,会用到container_of宏,通过调度实体找到task_struct,此宏的实现还是很经典的,我们来分析下此宏:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({			\
	const typeof(((type *)0)->member) * __mptr = (ptr);	\
	(type *)((char *)__mptr - offsetof(type, member)); })

此宏一共有三个参数,第一个为成员指针,第二个为结构体,第三个为成员名;
container_of(rt_se, struct task_struct, rt)
此处便是通过rt_se的指针找到其task_struct的指针,
其中__mptr 其实是对应的结构体成员指针的地址,而offsetof则是成员地址与结构体的起始地址的偏移量,两者的差值便是结构体的首地址;

4.enqueue_task与dequeue_task

这个是对于sched_rt_entity对哈希表的入队与出队操作,

在这里插入图片描述

enqueue_rt_entity函数通过调用list_head *queue = array->queue + rt_se_prio(rt_se)来找到对应的链表,找到后然后加入至对应的链表即可;

在这里插入图片描述

dequeue_task_rt是从实时队列中删除调度实体,主要包括update_curr_rt更新rt线程的运行时间信息,然后找到对应的链表,从链表中删除对应的节点即可;

5.yield_task

在这里插入图片描述

此函数功能为线程主动退出,原理也很简单,找到对应的链表,然后删除对应的节点即可;

6.SCHED_RR与SCHED_FIFO策略的联系

对于RT调度器实现了sched_rr与sched_fifo两种策略,都是通过链表进行管理的,我们在这先直接给出结论,后文会针对此进行代码实例化说明:
前提线程A与线程B的总时间大于100ms(一般都是满足的),因为100ms为rt调度器的默认调度时间片。
若两个优先级相同的的rr策略的线程,这个肯定是按照时间片依次执行。
若两个优先级相同的fifo策略线程,一个执行完才能到下一个线程。
若两个优先级相同的fifo与rr共存,谁先来谁先执行,比如rr先来,rr先执行100ms,然后fifo执行直到主动退出,然后才到rr执行完成,也就是说一到fifo拿到了执行权,必须等它执行完才可以。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值