进程及进程调度

简介: 1 .1 进程结构 每个进程都具有自己的属性,用一个task_struct数据结构来表示,它包含了进程的详细信息,主要有进程标识符(PID)、进程所占的内存区域、相关文件描述符、安全信息、进程环境、信号处理、资源安排、同步处理状态几个方面。

1 .1 进程结构

每个进程都具有自己的属性,用一个task_struct数据结构来表示,它包含了进程的详细信息,主要有进程标识符(PID)、进程所占的内存区域、相关文件描述符、安全信息、进程环境、信号处理、资源安排、同步处理状态几个方面。

数组task包含指向系统中所有task_struct结构的指针。创建进程时,Linux将从系统内存中分配一个task_struct结构,并将其加入task数组。操作系统初始化后,建立init进程,它建立一个task_struct数据结构INIT_TASK。当前运行进程的结构用current指针来指示。

进程切换包含三个层次:

1)用户数据的保存 包括正文段、数据段(DATA,BSS)、堆栈段(STACK)、共享内存段(SHARED MEMORY)。

2)寄存器数据的保护 包含PC、PSW(处理器状态字)、SP(栈指针)、PCBP(进程控制块指针)、FP(指向栈中一个函数的local变量的首地址)、P(指向栈中调用函数的实参位置)、ISP(中断栈指针),以及其他通用寄存器等。

3)系统级的保护 包括proc、u‘虚拟存储器空间管理表格、中断处理栈。

(PROC文件系统是Linux中的特殊文件系统,提供给用户一个可以了解内核内部工作过程的可读窗口,在运行时访问内核内部数据结构、改变内核设置的机制。)

 

状态为TASK_INTERRUPTBLE或TASK_UNINTERRUPTIBLE的睡眠进程得到它需要的资源被唤醒,通过schdule()进入TASK_RUNNING状态。状态TASK_UNINTERRUPTIBLE的睡眠进程,不能被信号或定时器中断唤醒,只有它申请的资源有效时才能被唤醒。

进程执行do_exit()后进入状态TASK_ZOMBILE,释放所申请的资源。

 1.2 进程的创建

1.2.1对象缓存的分配

在系统启动时的启动内核函数中,有进程管理的初始化函数,其中fork_init函数初始化线程数,分配进程结构的对象缓存。各个进程创建时进程结构对象从这里分配空间。

1.2.1系统调用sys_fork

当系统调用sys_fork创建一个进程的时候,它直接调用了实现函数do_fork。do_fork函数拷贝父进程的相关数据,如文件、信号量、内存等。完成进程初始化后,由父进程调用wake_up_process()函数将其唤醒,状态变为TASK_RUNNING,挂到就绪队列,返回子进程的pid。(创建完成的子进程会挂到就绪队列)

 1.3 内核线程

一个进程可以拥有多个线程。如果进程运行在SMP机器上,多个CPU执行各个线程,这样达到最大程度的并行。线程的上下文切换开销就比进程要小多了,线程共享了进程中除CPU以外的其他资源。

线程有内核线程、轻量级进程和用户线程三种,其中内核线程在内核调度,可并发使用多个处理器。用户线程在用户空间实现,它减少了上下文切换开销,它并行处理一个进程中的多个事务。

1)内核线程

内核线程是由内核创建和撤销的,用来执行一个指定的函数。内核线程共享内核的正文段内核全局数据,但各自具有自己的内核堆栈。它能够被单独调度,并且使用标准的内核同步机制,可以被单独分配到一个处理器上运行。内核线程实际上是一个与父进程共享地址空间的进程。

2)轻量级进程

轻量级进程是内核支持的用户线程。它在一个单独的进程中提供多线程控制。这些轻量级进程被单独调度,可以在多个处理器上运行,每一个轻量级进程都被绑定在一个内核线程上。轻量级进程不被独立调度,并且共享地址空间和进程中的其他资源,但是每个轻量级进程都应该有自己的程序计数器、寄存器集合、核心栈和用户栈。

3)用户线程

用户线程是通过线程库实现的。它们是在没有内核的参与下进行创建、释放和管理的。线程库提供了同步和调度的方法。用户线程的上下文在没有内核干预的情况下保存和恢复。每个用户线程可以有自己的用户堆栈,一块用来保存用户级寄存器上下文,以及入如信号屏蔽等状态信息的内存区。

内核只调度用户线程下的进程,这些进程再通过线程库函数来调度它们的线程。

 1.4 工作队列

工作队列接口是用于调度内核工作任务的。每个工作队列使用一个专门线程,所有来自运行队列的工作任务在这个线程中运行,而线程是在进程的上下文中运行的。因此可在适当时间调度此线程来运行工作任务。

 

 1.5 进程调度

在linux中,每一个CPU维护一个自己的runqueue结构的就绪队列。

1.5.1 runqueue结构

runqueue结构是主要的CPU运行队列数据结构。运行队列用来按照优先级来管理进程,每个运行队列代表一定优先级的进程的链表。与工作队列的区别是:一个工作队列运用一个线程来运行工作队列中的各种工作任务,而内核线程实质也是一种进程,工作队列与运行队列是完全不相关的两个概念。

1.5.2 进程调度初始化

linux的进程有schedule函数执行。它只在内核态运行,任何进程从系统调用返回时会转入schedule()。大多数中断服务程序在中断响应完成后,也会转入schedule().

1)调度器的初始化

函数sched_init初始化调度器

2)进程调度器相关环境的建立

函数sched_fork为进程p建立调度器相关环境,进程p是由当前进程用函数fork()新建的进程。

在进程创建fork系统调用中会调用do_fork函数,在do_fork函数中会调用到copy_process函数,而copy_process函数调用到了sched_fork函数,这说明进程创建时,就会建立调度器相关环境。shed_fork函数给进程p分配时间片,打上时间戳。

1.5.3 函数schedule分析

进程的调度有直接启动调度和被动调度两种方式,在不同的方式下调度执行的步骤是不一样的:

1)直接启动调度

直接启动调度发生在当前进程因资源而需要进入被阻塞状态时。调度程序执行的步骤如下:

a 把当前进程放到适当的等待队列里;

b 把当前进程的state设为TASK_INTERRUPTIBEL或者TASK_UNINTERRUPTIBEL;

c 调用schedule(),准备让新的进程掌握CPU

d 检查当前进程所需的资源是否可用,如果是,则把当前进程从等待队列里删除。

2)被动调度

通过在当前进程的need_resched设为1来实现被动调度,每次调入一个用户态进程之前,这个变量的值都会被检查,来决定是否调用函数schedule()来实现调度

函数schedule的功能是选择一个合适的进程在CPU上执行,它的基本流程分为五个操作步骤:

1)清理当前运行中的进程

2)选择下一个投入运行的进程

3)设置新进程的运行环境

4)执行进程上下文切换

5)后期整理

 1.6 Linux内核抢占

内核抢占就是让调度程序能尽可能多地运行,从而减少了从一个事件发生到调度程序被执行的时间延迟。在当前进程具有被“安全”抢占条件,并且有一个等待处理的重新调度请求时,内核就调用调度程序来进行进程调度。

内核抢占要求内核中所有可能为一个以上进程共享的变量和数据结构都要通过互斥机制加以保护,或者说都要放在临界区中。在抢占式内核中,认为如果内核不是在一个中断处理程序中,并且不在spinlock保护的代码中,就任务可以“安全”地进行切换。

抢占式内核实现的原理是在释放spinlock时,或者当中断返回时,如果当前执行进程的need_resched被标记,则进行抢占式调度。

 

 

 

 

 

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

热门文章

最新文章