Linux scheduler 调度器 (一)

前言

 为了解决资源少需求多的矛盾,“调度”应运而生。在生活中我们我们经常遇到调度的场景,比如物流公司根据客户需求的紧迫程度对车辆的调度,餐厅老板为了同时留住更多顾客对上餐顺序的调度等等。计算机领域也不例外,当待处理的任务个数远超过有限的计算资源(cpu个数)时,就需要调度器来同时满足多个任务的需求。内核调度器的目标只有一个,就是从众多任务中挑选出“最合适”的任务在cpu上运行。针对不同需求,各种调度器的的设计目标也会有所侧重,比如侧重于吞吐率、实时性、公平性等等。调度器是操作系统的一部分,如果说操作系统是将计算机的硬件资源进行抽象管理,那么调度器就是负责管理计算机的计算资源cpu。

内核调度器内部模块

假如我们从万米高空俯视Linux5.10调度器,它的内部结构如下所示:

调度类

一个系统中往往同时存在各种不同特性的任务,比如一些批处理任务运算量大但对实时性要求不高,再比如一些人机交互的任务要求响应及时,对实时性要求就比较高,所以不同的类型的任务就需要根据不同的调度策略做调度,不同的策略就需要不同的调度器算法来实现,Linux在2.6版本中引入了“调度类(Scheduling Class)”的概念,将调度器模块化,即抽象出各种调度器的通用行为,将调度策略封装到一个调度类 struct sched_class 的实例中,使得调度器核心代码不用再关心调度策略的具体细节,同时也方便了内核后续扩展增加其他调度器。关系如下:

调度类抽象出来的通用接口如下:

struct sched_class {
    void (*enqueue_task)(struct rq *rq, struct task_struct *p, int flags);
    //把任务p插入rq中的该调度器对应的就绪队列
    
    void (*dequeue_task)(struct rq *rq, struct task_struct *p, int flags);
    //把任务p移出就绪队列
        
    void (*yield_task)(struct rq *rq);
    //当前任务current主动释放CPU,但是其状态依然是runnable
    
    bool (*yield_to_task)(struct rq *rq, struct task_struct *p);
    //当前任务current主动释放CPU给任务p,但是其状态依然是runnable

    void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
    //检查进入runnable状态的p是否应该抢占该rq中的正在运行的current任务,如果是则做对应的处理。
    //比如刚唤醒一个任务时,为该任务选择了合适的rq,会检测该任务是否应该抢占该rq上的current任务,
    //如果应该抢占,那么就设置该current任务的TIF_NEED_RESCHED标志。

    struct task_struct *(*pick_next_task)(struct rq *rq);
    //从rq中选择出下一个要运行的任务

    void (*put_prev_task)(struct rq *rq, struct task_struct *p);
    void (*set_next_task)(struct rq *rq, struct task_str
  • 48
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值