Linux内核中的进程调度-调度器基础

目录

一、Linux内核中的调度器

1、调度器

1.1、概念

1.2、结构框图

1.3、Linux下的调度类介绍(sched_class)

1.5、调度优先级

1.6、调度策略

二、完全公平调度器(Completely Fair Scheduler, CFS)

1、CFS概念和特性

2、CFS如何实现“完全公平”

3、虚拟运行时间和真实运行时间的计算

三、实时调度器类

1、实时调度类

1.1、概念

1.2、实时调度实体

 1.3实时调度类

1.4、实时调度类和调度实体之间的关系 

2、实时调度类用到的调度策略

总结


一、Linux内核中的调度器

1、调度器

1.1、概念

        在Linux内核中,调度器(Scheduler)是操作系统内核的关键组件之一,负责管理和协调CPU资源在多个进程间高效、公正地分配。调度器的主要目标是确保CPU时间片能在系统中的各个进程间合理分配,从而最大化系统资源利用率,同时也要考虑进程的响应时间和整体系统性能。

1.2、结构框图

Linux内核中用来安排调度进程 (一段程序的执行过程) 执行的模块称为调度器(Scheduler),它可以切换进程状态 (Process status) 。比如: 执行、可中断睡眠、不可中断睡眠、退出、暂停等。

调度器是 CPU 中央处理器的管理员,主要负责完成做两件事情:
一、选择某些就绪进 程来执行。
二、是打断某些执行的进程让它们变为就绪状态。
调度器分配CPU 时间的基本依据:进程的优先级。
上下文 切换(context switch ):将进程在 CPU 中切换执行的过程,内核承担此任务,负责重建和存储被切换掉之前的CPU 状态。

1.3、Linux下的调度类介绍(sched_class)

①、sched_class数据结构介绍

调度类是内核调度框架中更为抽象的概念,它是一种组织和管理调度策略的结构化方式。在Linux内核中,每个调度类都对应一个具体的调度策略,或者一套相关的调度策略,并提供了一系列与调度相关的函数接口,如进程入队、出队、选择下一个运行进程等操作。

sched_class结构体是在代码中体现调度类,描述了调度器的基本操作接口,内核根据不同调度策略(如CFS、实时调度等)实现了对应的调度类,这些调度类则通过实现下面的接口来参与到内核的整体调度流程中。

数据结构定义在kernel/sched/sched.h

struct sched_class {

#ifdef CONFIG_UCLAMP_TASK
	int uclamp_enabled;
#endif
	/* 将进程加入到执行队列当中,即将调度实体(进程)存放到红黑树中,并对nr_running变量自动会加1*/
	void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);

	/* 从执行队列当中删除进程,并对nr_running变量自动减1 */
	void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
	
	/*放弃CPU执行权,实际上该函数执行先出队后入队,在这种情况下,它直接将调度实体放在红黑树的最右端 */
	void (*yield_task)   (struct rq *rq);
	bool (*yield_to_task)(struct rq *rq, struct task_struct *p);
	
	/* 用于检查当前进程是否可被新进程抢占 */
	void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
	
	/* 选择下一个应用要运行的进程*/
	struct task_struct *(*pick_next_task)(struct rq *rq);
	
	/*将进程放回到运行队列当中 */
	void (*put_prev_task)(struct rq *rq, struct task_struct *p);
	void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);

#ifdef CONFIG_SMP
	int (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);

	/* 为进程选择一个合适的CPU */
	int  (*select_task_rq)(struct task_struct *p, int task_cpu, int flags);
	struct task_struct * (*pick_task)(struct rq *rq);
	
	/* 迁移任务到另一个CPU */
	void (*migrate_task_rq)(struct task_struct *p, int new_cpu);
	
	/*专门用于唤醒进程 */
	void (*task_woken)(struct rq *this_rq, struct task_struct *task);
	
	/* 修改进程在CPU的亲和力 */
	void (*set_cpus_allowed)(struct task_struct *p,
				 const struct cpumask *newmask,
				 u32 flags);
	
	/* 启动运行队列 */
	void (*rq_online)(struct rq *rq);
	
	/* 禁止运行队列 */
	void (*rq_offline)(struct rq *rq);
	struct rq *(*find_lock_rq)(struct task_struct *p, struct rq *rq);
#endif
	/* 调用自time_tick函数,它可能引起进程切换,将驱动运行时(running)抢占 */
	void (*task_tick)(struct rq *rq, struct task_struct *p, int queued);

	/* 当进程创建的时候调用、不同调度策略的进程初始化也是不一样的*/
	void (*task_fork)(struct task_struct *p);
	
	/* 进程退出的时候使用*/
	void (*task_dead)(struct task_struct *p);

	/*
	 * The switched_from() call is allowed to drop rq->lock, therefore we
	 * cannot assume the switched_from/switched_to pair is serialized by
	 * rq->lock. They are however serialized by p->pi_lock.
	 */
	/* 专门用于进程的切换*/
	void (*switched_from)(struct rq *this_rq, struct task_struct *task);
	void (*switched_to)  (struct rq *this_rq, struct task_struct *task);
	
	/*进程优先级的更改 */
	void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
			      int oldprio);
	unsigned int (*get_rr_interval)(struct rq *rq,
					struct task_struct *task);
	void (*update_curr)(struct rq *rq);

#ifdef CONFIG_FAIR_GROUP_SCHED
	/* */
	void (*task_change_group)(struct task_struct *p);
#endif
};

比较重要的几个成员接口:

  • enqueue_task: 向就绪队列添加一个进程,某个任务进入可运行状态时,该函数将会调用,它将调度实体放入到红黑树当中。
  • dequeue_task: 将一个进程从就绪队列中进行删除,当某个任务退出可运行状态时调用该函数,将从红黑树中去掉对应调度实体。
  • yield_task:在进程想要资源放弃对处理器的控制权时,可使用在sched_yiled系统调用,会调用内核API去处理操作。
  • check_preempt_curr
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值