进程调度(四)

简介: 版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/46603765 紧接上一篇...
版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/46603765

紧接上一篇!!

(二)抢占和进程上下文

上下文切换,就是从一个可执行进程切换到另一个可执行进程,由定义在kernel/sched.c中的context_switch()函数处理,该函数主要完成两项基本工作:

​1:调用声明在asm/mmu_context.h中的switch_mm(),该函数负责把虚拟内存从上一个进程映射切换到新进程中。
​2:调用声明在asm/system.h文件中的switch_to()函数,该函数负责从上一个进程的处理器状态切换到新进程的处理器状态。这包括保存,恢复栈信息和寄存器信息,还有其他任何与体系结构相关的信息,都必须以每一个进程为对象进行管理和保存。

下面我们看一下函数context_switch()的代码:

/*
 * context_switch - switch to the new MM and the new
 * thread's register state.
 *
 * context_switch - 切换到一个新的MM(内存)和新的进程
 * 的寄存器状态
 */
static inline void
context_switch(struct rq *rq, struct task_struct *prev,
           struct task_struct *next)
{
    struct mm_struct *mm, *oldmm;
    prepare_task_switch(rq, prev, next);
    trace_sched_switch(rq, prev, next);
    mm = next->mm;
    oldmm = prev->active_mm;
    /*
     * For paravirt, this is coupled with an exit in switch_to to
     * combine the page table reload and the switch backend into
     * one hypercall.
     */
    arch_start_context_switch(prev);
    if (likely(!mm)) {
        next->active_mm = oldmm;
        atomic_inc(&oldmm->mm_count);
        enter_lazy_tlb(oldmm, next);
    } else
        switch_mm(oldmm, mm, next);
    if (likely(!prev->mm)) {
        prev->active_mm = NULL;
        rq->prev_mm = oldmm;
    }
    /*
     * Since the runqueue lock will be released by the next
     * task (which is an invalid locking op but in the case
     * of the scheduler it's an obvious special-case), so we
     * do an early lockdep release here:
     */
#ifndef __ARCH_WANT_UNLOCKED_CTXSW
    spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
#endif
    /* Here we just switch the register state and the stack. */
    switch_to(prev, next, prev); //切换处理器状态,并保存上一个进程的处理器状态
    barrier();
    /*
     * this_rq must be evaluated again because prev may have moved
     * CPUs since it called schedule(), thus the 'rq' on its stack
     * frame will be invalid.
     */
    finish_task_switch(this_rq(), prev);
}

下面我们来整体的看一下休眠和唤醒的函数调用和过程:

这里写图片描述

内核提供need_resched变量来表明函数是否需要重新进行一次调度,下面是用于访问和操作need_resched变量的函数。

这里写图片描述

在返回用户空间以及从中断返回的时候,内核也会检查need_reched标志,如果已被设置,内核会在继续执行之前调用调度程序。

每个进程都有一个need_resched标志,这是因为访问进程描述符内的数值比访问一个全局变量快。

​1:用户抢占
内核即将返回用户空间的时候,如果need_resched标志被设置,会导致schedule()被调用,此时就会发生用户抢占。

用户抢占在一下情况下发生:
​1:从系统调用返回用户空间的时候
​2:从中断处理函数返回用户空间的时候

2:内核抢占

Linux完整的支持内核抢占,但是,由于内核抢占会出现一些安全性问题,那么,内核抢占时机的确定是相当重要的,那么什么时候进行重新调度是安全的呢?只要没有锁,内核进可以进行抢占。

Linux为了支持内核抢占,在thread_info中引入了preempt_count计数器。该计数器的初始值为0,每当使用锁的时候,该值加1,当释放锁的时候,该值减1,当该数值为0的时候,内核就可以抢占。当从中断返回内核空间的时候,内核就会检查need_resched标志和preempt_count计数器。如果need_resched标志被设置,并且preempt_count数值为0,调度程序就会被执行。

如果此时的preempt_count不为0,说明当前任务持有锁,所以抢占是不安全的。 这时,内核就会像通常那样直接从中断返回当前执行进程。如果当前执行进程持有的所有的锁都被释放了,preempt_count数值为0,此时,释放锁的代码就会检查need_resched标志是否被设置,如果被设置的话,就会调用调度程序。

内核抢占发生的时间:

​1:中断处理程序正在执行,且返回内核空间之前
​2:内核代码再一次具有可抢占性的时候
​3:如果内核中的任务显示的调用schedule()函数
​4:如果内核中的任务阻塞                                   

(二):实时调度策略
Linux提供了两种实时调度策略:SCHED_FIFO和SCHED_RR,而普通的,非实时的调度策略是SCHED_NORMAL。这些实时调度策略被是个特殊的实时调度器管理,定义在kernel/sched_rt.c中。

​1:SCHED_FIFO

​这是一个先入先出的调度算法,他不使用时间片。处于可运行状态的SCHED_FIFO级进程会比任何SCHED_NORMAL进程都先得到调度。一旦一个SCHED_FIFO进程处于可执行状态,就会一直执行下去,只有更高优先级的SCHED_FIFO和SCHED_RR任务才能抢占SCHED_FIFO任务。如果有两个或多个同优先级的SCHED_FIFO级进程,他们会轮流执行,但是依然只有他们愿意让出处理器的时候才会退出。只要有SCHED_FIFO级进程在执行,其他级别较低的进程就只能等待他变为不可运行状态后才有机会执行。

​2:SCHED_RR

SCHED_RR和SCHED_FIFO大体相同,只是 SCHED_RR级的进程在耗尽事先分配给他的时间后就不在继续执行了,也就是说SCHED_RR是带有时间片的SCHED_FIFO,这是一种实时轮流调度算法。当SCHED_RR任务耗尽他的时间片的时候,在同一优先级的其他实时进程被轮流调度。时间片只用来重新调度同一优先级的进程。对于SCHED_FIFO进程,高优先级进程总是立即抢占低优先级,但是低优先级决不能抢占SCHED_RR任务,即使他的时间片耗尽。

Linux的实时调度算法提供了一种软实时工作方式。软实时的含义是,内核调度进程,尽力使进程在他的限定时间到来之前运行,但内核不保证总能满足这些进程的要求。

实时优先级范围是从0到MAX_RT_PRIO-1。默认情况下,MAX_RT_PRIO为100,所以默认的实时优先级的范围是0-99.SCHED_NORMAL级进程的nice值共享了这个取值空间,他的取值范围是从MAX_RT_PRIO到(MAX_RT_PRIO+40)。也就是说,在默认情况下,nice值从-20到+19直接对应的是从100-139的实时优先级范围。

(三):与调度相关的系统调用
Linux提供了一个系统调用族,用于管理与调度程序相关的参数。下面我们来看一下系统调用。

这里写图片描述

Linux调度程序提供强制的处理器绑定(processor affinity)机制。也就是说,他允许用户强制指定”这个进程必须在这些处理器上执行“。这种强制的亲和性保存在进程的task_struct结构中的cpus_allowed这个位掩码标志中。该掩码标志的每一位对应一个系统可用的处理器。默认情况下,所有的位都被设置,进程可以在系统中所有可用的处理器上执行。用户可以通过sched_setaffinity()设置不同的一个或几个位组合的掩码,而调用sched_getaffinity()则返回当前的cpus_allowed位掩码。

Linux通过sched_yield()系统调用,提供了一种让进程显示地将处理器时间让给其他等待执行进程的机制。

目录
相关文章
|
算法 调度 UED
深入理解操作系统:进程调度与优先级队列
【10月更文挑战第31天】在计算机科学的广阔天地中,操作系统扮演着枢纽的角色,它不仅管理着硬件资源,还为应用程序提供了运行的环境。本文将深入浅出地探讨操作系统的核心概念之一——进程调度,以及如何通过优先级队列来优化资源分配。我们将从基础理论出发,逐步过渡到实际应用,最终以代码示例巩固知识点,旨在为读者揭开操作系统高效管理的神秘面纱。
|
5月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
158 0
|
12月前
|
消息中间件 算法 调度
深入理解操作系统:进程管理与调度
操作系统是计算机系统的核心,负责管理和控制硬件资源、提供用户接口以及执行程序。其中,进程管理是操作系统的重要组成部分,它涉及到进程的创建、调度、同步和通信等方面。本文将深入探讨进程管理的基本概念、进程调度算法以及进程间的同步和通信机制。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程管理的基本技能。
183 11
|
11月前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
12月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
操作系统作为计算机系统的核心,其进程管理和调度策略对于系统性能和用户体验至关重要。本文将通过直观的代码示例和浅显易懂的语言,带领读者了解操作系统如何有效管理进程以及常见的进程调度算法。我们将从进程的基本概念出发,逐步深入到进程状态、进程控制块(PCB)的作用,最后探讨不同的调度算法及其对系统性能的影响。无论您是初学者还是有一定基础的开发者,都能从中获得有价值的信息。
|
12月前
|
负载均衡 算法 调度
深入理解操作系统:进程管理与调度
在数字世界的心脏,操作系统扮演着至关重要的角色。它如同一位精明的指挥家,协调着硬件资源和软件需求之间的和谐乐章。本文将带你走进操作系统的核心,探索进程管理的艺术和调度策略的智慧。你将了解到进程是如何创建、执行和消亡的,以及操作系统如何巧妙地决定哪个进程应该在何时获得CPU的青睐。让我们一起揭开操作系统神秘的面纱,发现那些隐藏在日常计算背后的精妙机制。
|
12月前
|
调度 开发者
深入理解操作系统之进程调度
在计算机科学领域,操作系统是核心的一环,它管理着计算机硬件资源,并提供接口供上层软件运行。本文将通过深入浅出的方式,探讨操作系统中至关重要的一个概念——进程调度。我们将从基础理论出发,逐步展开讲解进程调度的原理和实现,并配以实际代码示例,旨在帮助读者更好地理解和掌握这一主题。文章不仅适合初学者建立基础,也适合有一定基础的开发者深化理解。
|
12月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第40天】在数字世界中,操作系统是连接硬件与软件的桥梁,它管理着计算机资源和提供用户服务。本文将深入探讨操作系统中的进程管理与调度策略,揭示它们如何协调多任务运行,保证系统高效稳定运作。通过代码示例,我们将展示进程创建、执行以及调度算法的实际应用,帮助读者构建对操作系统核心机制的清晰认识。
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第34天】本文旨在探讨操作系统中至关重要的一环——进程管理及其调度策略。我们将从基础概念入手,逐步揭示进程的生命周期、状态转换以及调度算法的核心原理。文章将通过浅显易懂的语言和具体实例,引导读者理解操作系统如何高效地管理和调度进程,保证系统资源的合理分配和利用。无论你是初学者还是有一定经验的开发者,这篇文章都能为你提供新的视角和深入的理解。
122 3
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
224 4

热门文章

最新文章