[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制

Linux 内核作为一个多任务操作系统,其进程管理子系统是核心组成部分之一。无论是用户应用的运行、驱动行为的触发,还是系统调度决策,几乎所有操作都离不开进程的创建、调度与销毁。本文将从进程的概念出发,深入探讨 Linux 内核中进程管理的架构、关键结构体、核心函数以及调度机制,帮助读者全面理解进程管理的内部实现。


1️⃣ 进程管理概述

1.1 什么是进程管理?

在操作系统中,进程是资源分配和调度的基本单位。Linux 内核通过进程管理子系统实现对进程的创建、调度、同步和终止等操作。掌握进程管理,有助于深入理解内核的调度策略与系统行为,在嵌入式开发、系统调试、驱动开发与性能调优等方面提供底层逻辑支持。

1.2 Linux 进程管理架构概览

Linux 内核的进程管理架构主要包括以下模块:

模块名称核心职责关键结构 / 函数示例相关源码位置
进程描述结构体描述进程状态、资源、调度信息task_structthread_infoinclude/linux/sched.h
进程创建机制创建进程、复制上下文、初始化资源fork()do_fork()copy_process()kernel/fork.c
程序执行加载替换进程地址空间并执行新程序execve()do_execveat_common()fs/exec.ckernel/exec_domain.c
进程退出机制释放资源、通知父进程、进入僵尸态exit()do_exit()release_task()kernel/exit.c
进程调度器管理调度实体、决定谁运行、支持多种调度策略schedule()、CFS、rqsched_classkernel/sched/core.cfair.c
上下文切换切换执行流、保存/恢复 CPU 状态context_switch()switch_to()kernel/sched/core.carch/*/kernel/
进程状态管理控制进程运行/睡眠/终止状态,便于调度与同步TASK_RUNNINGTASK_INTERRUPTIBLEinclude/linux/sched.h
阻塞与唤醒机制通过等待队列控制休眠/唤醒流程,协调资源争用wait_queue_head_twake_up()kernel/sched/wait.cinclude/linux/wait.h
调度策略与优先级支持普通、实时调度,动态调整权重与时间片SCHED_NORMALSCHED_FIFOnicekernel/sched/ 各调度策略子模块
用户态/内核态交互系统调用入口、堆栈切换、权限切换sys_clone()do_syscall_64()arch/arm64/kernel/entry.Skernel/

2️⃣ 进程的状态

在 Linux 中,进程的状态主要包括:

  • TASK_RUNNING:可运行状态,正在运行或准备运行。
  • TASK_INTERRUPTIBLE:可中断睡眠状态,等待某事件发生。
  • TASK_UNINTERRUPTIBLE:不可中断睡眠状态,通常用于等待 I/O 操作完成。
  • TASK_STOPPED:停止状态,进程被暂停。
  • TASK_TRACED:被跟踪状态,进程正在被调试。
  • EXIT_ZOMBIE:僵尸状态,进程已终止但尚未被父进程回收。
  • EXIT_DEAD:死亡状态,进程资源已被释放。

这些状态的转换由内核调度器根据系统资源和进程行为进行管理。


3️⃣ 进程管理核心架构

3.1 task_struct 结构体

内核通过 task_struct 结构体来描述一个进程,它被称为进程描述符(Process Descriptor),保存着支撑一个进程正常运行的所有信息。
在这里插入图片描述

task_struct 包含的信息包括:

  • 进程状态(如运行、睡眠等)
  • 进程标识符(PID)
  • 父子进程关系
  • 调度信息(如优先级、调度策略)
  • 内存管理信息(如地址空间)
  • 文件系统信息(如打开的文件)
  • 信号处理信息
  • 安全信息(如权限)

通过 task_struct,内核可以全面管理和调度进程。

3.2 核心函数

3.2.1 kernel_clone()

kernel_clone() 是 Linux 内核中用于创建新进程或线程的核心函数之一,广泛用于内核线程创建、系统调用 clone()clone3() 的实现中。它负责准备和校验参数、决定是否进行 ptrace 跟踪、调用 copy_process() 完成进程复制,并处理进程唤醒与后续收尾逻辑。

其主要步骤包括:

  1. 参数校验,防止 CLONE_PIDFDCLONE_PARENT_SETTID 指向同一地址。
  2. 判断是否需要触发 ptrace 跟踪事件,如 PTRACE_EVENT_FORKCLONEVFORK
  3. 调用 copy_process() 创建并初始化新进程的 task_struct
  4. 添加系统熵,增强内核熵池。
  5. 调度器事件追踪,记录进程创建事件。
  6. 获取新进程的 PID,并根据需要写入 parent_tid
  7. 若设置了 CLONE_VFORK,初始化同步机制,并在父进程阻塞等待。
  8. 若未共享地址空间(非 CLONE_VM),设置内存 LRU 跟踪。
  9. 唤醒新创建的子进程,启动任务调度。
  10. 如果启用了 ptrace 事件,发送通知。
  11. 如果是 vfork,阻塞当前进程直到子进程释放 VM。
  12. 释放 PID 引用,防止内存泄漏。
  13. 返回子进程 PID。
3.2.2 copy_process()

copy_process() 是内核创建新进程(包括 fork、vfork、clone 和内核线程)的核心函数,它的实现逻辑极其庞大。其主要职责包括:

  1. 复制当前进程的 task_struct 结构体,分配内存并初始化任务栈。
  2. 复制用户凭据(uid/gid/capability),对应 clone_flagsCLONE_NEWUSER 等。
  3. 初始化延迟统计结构,仅用于性能跟踪。
  4. 调度器层面初始化新任务,分配调度相关结构。
  5. 初始化 perf 事件跟踪数据,支持性能事件分析。
  6. 分配审计信息结构,针对安全模块。
  7. 安全模块初始化,如 SELinux,与 LSM(Linux 安全模块)有关。
  8. 复制 SYSV 信号量取消状态,若使用信号量。
  9. 文件描述符表复制,区分共享与独立 fd 表。
  10. 复制 fs_struct(cwd/root 等),控制工作目录和挂载点的继承。
  11. 复制信号处理函数表,若不共享 sighand(CLONE_SIGHAND)。
  12. 创建新的 signal_struct(信号相关状态)

接续上文,本文将继续深入探讨 Linux 内核进程管理的关键机制,包括进程调度策略、上下文切换过程以及相关核心结构体的作用。


4️⃣ 进程调度机制

4.1 调度的基本概念

进程调度的核心任务是决定哪个进程在何时运行。调度器依据一定的策略,从就绪队列中选择一个进程分配 CPU 时间。调度策略的设计直接影响系统的响应速度、吞吐量和公平性。

4.2 调度策略分类

Linux 内核支持多种调度策略,主要包括:

  • SCHED_NORMAL(或 SCHED_OTHER):默认的时间共享调度策略,适用于普通进程。
  • SCHED_BATCH:适用于批处理作业,优化吞吐量。
  • SCHED_IDLE:用于系统空闲时运行的低优先级任务。
  • SCHED_FIFO 和 SCHED_RR:实时调度策略,适用于对响应时间有严格要求的任务。
  • SCHED_DEADLINE:基于截止时间的调度策略,适用于具有明确时间约束的任务。

4.3 完全公平调度器(CFS)

CFS(Completely Fair Scheduler)是 Linux 内核自 2.6.23 版本起引入的默认调度器,旨在为所有进程提供公平的 CPU 时间分配。([linux-audit.com][1])

4.3.1 核心理念

CFS 模拟一个理想的多任务处理器,假设所有进程可以同时并行运行。由于实际硬件无法实现真正的并行,CFS 引入了“虚拟运行时间”(vruntime)的概念,用于衡量进程的实际运行时间与其应得运行时间之间的差距。([zh.wikipedia.org][2])

4.3.2 数据结构

CFS 使用红黑树(Red-Black Tree)作为就绪队列的数据结构,每个节点表示一个可调度实体(sched_entity),按照 vruntime 进行排序。调度器总是选择 vruntime 最小的进程进行调度。

4.3.3 时间片计算

CFS 不使用固定的时间片,而是根据系统的目标延迟(target latency)和就绪队列中的进程数量动态计算每个进程的时间片,确保每个进程在目标延迟内至少运行一次。([medium.com][3])


5️⃣ 上下文切换机制

5.1 上下文切换的定义

上下文切换是指操作系统保存当前运行进程的状态,并恢复另一个进程的状态,使其能够继续执行的过程。这是实现多任务处理的基础。

5.2 上下文切换的触发时机

上下文切换可能在以下情况下发生:

  • 当前进程主动放弃 CPU(例如,调用 schedule())。
  • 当前进程被阻塞(例如,等待 I/O 操作完成)。
  • 系统发生中断或异常。
  • 当前进程的时间片耗尽。

5.3 上下文切换的实现过程

在 Linux 内核中,上下文切换主要由 context_switch() 函数完成,其过程包括:

  1. 调用 prepare_task_switch() 准备切换。
  2. 调用 arch_start_context_switch() 执行架构相关的切换操作。
  3. 根据需要切换内存地址空间(即更新页表)。
  4. 保存当前进程的寄存器状态。
  5. 恢复目标进程的寄存器状态。
  6. 调用 finish_task_switch() 完成切换。([linux-kernel-labs.github.io][4])

整个过程确保了进程的执行环境被完整保存和恢复,实现了进程之间的无缝切换。


6️⃣ 调度相关的核心结构体

6.1 sched_class

sched_class 是一个结构体,定义了调度器的行为和操作函数指针,如选择下一个任务、任务入队出队等。不同的调度策略(如 CFS、实时调度器)通过实现各自的 sched_class 来定义其调度逻辑。

6.2 sched_entity

sched_entitytask_struct 中的一个成员,表示一个可调度的实体,包含了调度相关的信息,如 vruntime、权重等。在 CFS 中,调度器通过操作 sched_entity 来管理进程的调度。


7️⃣ 总结

Linux 内核的进程管理机制涵盖了从进程的创建、调度到终止的完整生命周期。通过深入理解 task_structkernel_clone()copy_process()、CFS 调度器以及上下文切换的实现,可以更好地掌握内核的工作原理,为系统优化和问题排查提供坚实的基础。

希望本文能帮助您构建起完整的进程管理知识体系,深入理解 Linux 内核的精妙设计。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/908593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第16节 Node.js 文件系统

Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API。 Node 导入文件系统模块(fs)语法如下所示: var fs require("fs") 异步和同步 Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本&#xff…

《探秘局域网广播:网络世界的 “大喇叭”》

揭开局域网广播的神秘面纱 在当今数字化时代,网络已成为人们生活和工作中不可或缺的一部分。从日常的网页浏览、社交媒体互动,到企业级的数据传输、云计算应用,网络通信无处不在。在这个庞大而复杂的网络世界里,数据如同信息流在各个节点之间穿梭,而局域网广播则是其中一种…

基于Ubuntu22.04安装SVN服务器之仓库迁移

基于Ubuntu22.04安装SVN服务器之仓库迁移 第一步: 停止svn服务器 第一步: 停止svn服务器 1)建议迁移的时候先把SN服务器停掉,以免操作失败。 svnserve -d -r /usr/svn第二步:dump出svn代码库 1)通过dump出旧的svn服务器上的代码…

Unity UI 性能优化终极指南 — Image篇

🎯 Unity UI 性能优化终极指南 — Image篇 🧩 Image 是什么? Image 是UGUI中最常用的基本绘制组件支持显示 Sprite,可以用于背景、按钮图标、装饰等是UI性能瓶颈的头号来源之一,直接影响Draw Call和Overdraw &#x1…

「Java基本语法」代码格式与注释规范

Java代码的基本格式 Java代码的规范格式是编写和维护Java程序的基础,其中包括类定义、方法定义、代码缩进、大括号位置等。 1.核心规则 每个Java文件必须包含一个公共类(public class),且Java源文件的文件名必须和这…

2025年AI编程工具推荐

目录 👑 **一、全能型AI开发环境(IDE)**🛠️ **二、AI代码助手与插件**🎯 **三、垂直领域工具**🇨🇳 **四、国产工具精选**🔮 **五、创新前沿工具**⚖️ **选型建议** 2025年&#x…

【工具使用】STM32CubeMX-FreeRTOS操作系统-信号标志、互斥锁、信号量篇

一、概述 无论是新手还是大佬,基于STM32单片机的开发,使用STM32CubeMX都是可以极大提升开发效率的,并且其界面化的开发,也大大降低了新手对STM32单片机的开发门槛。     本文主要讲述STM32芯片FreeRTOS信号标志、互斥锁和信号…

ArrayList和LinkedList(深入源码加扩展)

ArrayList 和 LinkedList 是 Java 集合框架中两种常用的列表实现,它们在底层数据结构、性能特点和适用场景上有显著的区别。以下是它们的详细对比以及 ArrayList 的扩容机制。 1. ArrayList 和 LinkedList 的底层区别 (1) 底层数据结构 ArrayList: 基于动态数组(Dynamic Ar…

浅谈 React Suspense

React Suspense 是 React 中用于处理异步操作的功能。它可以让你"等待"某些操作,如数据获取或组件加载完成,然后再渲染组件。Suspense 的核心理念是让组件在准备好之前显示一个备用的 UI,例如加载指示器,从而提高用户体…

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…

Linux【4】------RK3568启动和引导顺序

引导顺序 RK3568 的启动流程如下: 加电后,芯片首先执行 BootROM 中的代码; BootROM 会尝试从配置好的外部设备(如 NOR/NAND/eMMC/SD 卡)加载启动程序; 如果这些设备都没有有效的启动代码,Bo…

Deepseek/cherry studio中的Latex公式复制到word中

需要将Deepseek/cherry studio中公式复制到word中,但是deepseek输出Latex公式,比如以下Latex代码段,需要通过Mathtype翻译才能在word中编辑。 $$\begin{aligned}H_1(k1) & H_1(k) \frac{1}{A_1} \left( Q_1 u_1(k) Q_{i1} - Q_2 u_2(k…

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…

【机器学习】支持向量机实验报告——基于SVM进行分类预测

目录 一、实验题目描述 二、实验步骤 三、Python代码实现基于SVM进行分类预测 四、我的收获 五、我的感受 一、实验题目描述 实验题目:基于SVM进行分类预测 实验要求:通过给定数据,使用支持向量机算法(SVM)实现分…

前端开发面试题总结-JavaScript篇(二)

文章目录 其他高频问题15、JS的数据类型有哪些16、如何判断数组类型?17、解释 this 的指向规则18、跨域问题及解决方案19、宏任务与微任务的区别是什么?列举常见的宏任务和微任务。20、为什么微任务的优先级高于宏任务?设计目的是什么&#x…

硬件电路设计-开关电源设计

硬件电路设计-开关电源 电容选取设置输出电压电感的选取PCB布局典型电路 这里以杰华特的JW5359M 开关电源为例,介绍各个部分的功能电路。 当EN引脚电压低于0.4V时,整个稳压器关闭,稳压器消耗的电源电流降至1μΑ以下 电容选取 1.C1和C25构成…

phosphobot开源程序是控制您的 SO-100 和 SO-101 机器人并训练 VLA AI 机器人开源模型

​一、软件介绍 文末提供程序和源码下载 phosphobot开源程序是控制您的 SO-100 和 SO-101 机器人并训练 VLA AI 机器人开源模型。 二、Overview 概述 🕹️ Control your robot with the keyboard, a leader arm, a Meta Quest headset or via API 🕹️…

数据通信基础

信道特性 1.信道带宽W • 模拟信道:Wf2-f1(f2和f1分别表示:信道能通过的最高/最低频率,单位赫兹Hz)。 • 数字信道:数字信道是离散信道,带宽为信道能够达到的最大数据传输速率,单位…

C++与Python编程体验的多维对比:从语法哲学到工程实践

引言:语言定位的本质差异 作为静态编译型语言的代表,C以0开销抽象原则著称,其模板元编程能力可达图灵完备级别,而Python作为动态解释型语言,凭借鸭子类型和丰富的标准库成为快速开发的首选。这种根本差异导致两种语言…

TP6 实现一个字段对数组中的多个值进行LIKE模糊查询(OR逻辑)

在ThinkPHP6中,可以通过以下方式实现一个字段对数组中的多个值进行LIKE模糊查询(OR逻辑): 1,使用数组形式的where条件,通过第三个参数指定逻辑关系: $where[] [字段名, like, [%值1%, %值2%]…