禅与计算机 禅与计算机
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机组成原理

  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • 浅谈Linux权限管理
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
      • 引言
      • 详解进程的基本概念
        • 进程基本介绍
        • 进程内存空间分配算法
        • 进程空间结构
        • 进程的调度算法
      • 详解操作系统中线程的基本概念
        • 什么是线程
        • 线程的基本结构
        • 线程解决了什么问题
        • CPU如何调度指挥线程
        • 进程的创建与状态转换
        • 线程同步机制
        • 进程间通信(IPC)
      • 小结
      • 参考
    • Linux进程间通信机制
    • 浅谈Linux基于信号处理中断的哲学
    • 从操作系统底层浅谈程序栈的高效性
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
    • 来聊聊函数回调
    • 一个完美主义者的自我救赎
  • 计算机网络

  • 运维

  • 编码最佳实践

  • 计算机基础
  • 操作系统
sharkchili
2026-03-25
目录

进程与线程深度解析

[toc]

# 引言

进程和线程是操作系统中两个核心概念,它们构成了现代多任务操作系统的基础。理解它们的区别和联系对于系统编程、性能优化和故障排查都至关重要。

在本文中,我们将深入探讨进程和线程的基本概念、内存管理、调度机制以及它们在Linux系统中的具体实现。

# 详解进程的基本概念

# 进程基本介绍

进程是程序的一次执行实例,它包含了程序执行时所需的所有资源。在现代操作系统中,进程是资源分配的基本单位。在Linux系统中,无论是进程还是线程,都是通过task_struct结构来管理的,它们都可以被调度执行,因此进程和线程在内核中都被称为任务(task),线程也被称为轻量级进程(Lightweight Process)。系统中同时运行着成百上千个进程,每个进程都有独立且唯一的进程ID(PID)。我们可以通过ps -ef或top命令查看正在运行的进程,其中PID列显示的就是进程ID。

在Linux系统中,第一个启动的进程通常是systemd(PID为1),它是所有用户进程的祖先进程:

sharkchili@xxx:~$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 Sep15 ?        00:01:41 /usr/lib/systemd/systemd --system --deserialize=104
root           2       1  0 Sep15 ?        00:00:00 /init
1
2
3
4

我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:https://github.com/shark-ctrl/mini-redis。

为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。

# 进程内存空间分配算法

在早期的计算机系统中,进程直接使用物理地址访问内存,这导致了严重的安全和稳定性问题。一个进程可能会意外或恶意地访问其他进程的内存空间,造成系统崩溃或数据泄露。

为了解决这个问题,现代操作系统引入了虚拟内存机制。虚拟内存为每个进程提供了一个独立的、逻辑上连续的地址空间,使得每个进程都"认为"自己拥有整个系统的内存资源。当进程访问内存时,内存管理单元(MMU)会将进程的虚拟地址转换为实际的物理地址。这种地址转换机制不仅隔离了不同进程的内存空间,还提供了内存保护功能,防止进程间相互干扰。

# 进程空间结构

进程的内存空间结构相对复杂,主要包括以下几个部分:

  1. 代码段(Text Segment):存放程序的可执行指令
  2. 数据段(Data Segment):存放已初始化的全局变量和静态变量
  3. BSS段(Block Started by Symbol):存放未初始化的全局变量和静态变量
  4. 堆(Heap):进程动态分配的内存区域,向高地址增长
  5. 栈(Stack):存放函数调用的上下文信息,向低地址增长
  6. 内存映射区(Memory Mapping Segment):通过mmap系统调用映射的文件或其他内存对象
  7. 内核空间(Kernel Space):操作系统内核使用的内存区域,普通进程无法直接访问

在Linux中,进程和线程切换都涉及上下文切换(Context Switching)。上下文切换是指CPU从一个进程或线程切换到另一个进程或线程时保存和恢复执行状态的过程。切换过程包括:

  • 保存当前进程/线程的CPU寄存器状态在进程的内核栈和task_struct->thread结构体中
  • 更新内存管理单元(MMU)的页表
  • 加载下一个进程/线程的寄存器状态
  • 恢复下一个进程/线程的执行

上下文切换虽然是多任务系统的基础,但也会消耗系统资源。频繁的上下文切换会降低系统性能,因此操作系统会通过调度算法和时间片分配来平衡响应性和效率。

进程在运行过程中会频繁访问代码段、堆和栈中的数据。当进程需要更多内存时,必须通过系统调用向操作系统申请,如果进程试图访问未分配的内存区域,则会收到段错误(Segmentation fault)并被操作系统终止。此外,用户态进程无法直接访问内核空间,必须通过系统调用进入内核态才能访问内核数据结构:

# 进程的调度算法

操作系统采用多种调度算法来平衡系统性能、响应时间和公平性。常见的调度策略包括:

  1. 时间片轮转:每个进程被分配一个固定的时间片,当时间片用完时,操作系统会触发时钟中断,保存当前进程的上下文,并切换到下一个就绪进程
  2. 优先级调度:高优先级的进程会优先获得CPU执行权
  3. 多级反馈队列:结合时间片轮转和优先级调度的优点,根据进程的行为动态调整其优先级

Linux内核使用完全公平调度器(CFS)作为默认的调度算法,它通过红黑树数据结构维护就绪队列,确保所有进程都能获得公平的CPU时间:

通过合理使用中断机制和调度算法,操作系统能够在保证公平性的同时最大化CPU的利用率,为用户提供流畅的多任务体验。

# 详解操作系统中线程的基本概念

# 什么是线程

进程作为资源分配的基本单位,其创建和上下文切换的开销较大。为了提高程序的并发性能,操作系统引入了线程的概念。线程是进程内的执行单元,在Linux中线程被实现为轻量级进程,与进程一样通过task_struct结构进行管理。线程是CPU调度的基本单位,也是CPU能够分配资源的最小单位。

同一进程内的多个线程共享进程的内存空间(代码段、数据段、堆等)和文件描述符等资源,但每个线程拥有独立的栈空间、程序计数器(PC)、寄存器状态和调度优先级。这种设计既保持了进程间的隔离性,又实现了线程间的高效协作。在多核处理器系统中,多个线程可以真正并行执行,充分利用硬件资源:

# 线程的基本结构

在Linux系统中,线程和进程使用相同的数据结构task_struct来表示。这是因为在Linux内核中,线程被视为一种特殊的轻量级进程(Lightweight Process)。Linux采用统一的调度实体(schedulable entity)模型,无论是进程还是线程都通过task_struct结构进行管理。

在同一个线程组中,所有线程共享相同的tgid(线程组ID),该值等于主线程的pid。每个线程仍具有唯一的pid用于内核调度。以下是task_struct结构体的部分字段定义(简化版):

// task_struct结构体定义(简化版)
struct task_struct {
    // 进程标识符
    pid_t pid;                              // 任务ID(每个线程/进程唯一)
    pid_t tgid;                             // 线程组ID(同一线程组共享)
    struct task_struct *group_leader;       // 线程组领导者

   //......

    // 内存管理
    struct mm_struct *mm;                   // 内存描述符(线程组共享)
    struct mm_struct *active_mm;            // 激活的内存描述符

    // 调度相关
    struct sched_entity se;                 // 调度实体
    struct sched_rt_entity rt;              // 实时调度实体
    int prio;                               // 优先级
    int static_prio;                        // 静态优先级
    int normal_prio;                        // 正常优先级

    // 时间相关
    u64 utime, stime, gtime;                // 用户态/内核态/子进程时间
    unsigned long nvcsw, nivcsw;            // 自愿/非自愿上下文切换次数

   //......
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

这种设计使得线程和进程在内核中的管理方式保持一致,同时通过共享内存描述符(mm_struct)实现线程间的内存共享。

# 线程解决了什么问题

早期的进程都是单一执行流,当应用程序需要处理复杂的并发任务时,就必须创建多个进程来完成。例如,一个进程负责读取文件,另一个进程负责写入文件。但由于进程间切换的开销很大,这种方式效率低下。

为了解决这个问题,操作系统设计者提出了在同一进程内创建多个执行流的想法,这些执行流可以共享进程的数据和资源,从而大大减少了上下文切换的开销。这就衍生出了多线程的概念:

# CPU如何调度指挥线程

在多核CPU系统中,每个CPU核心通常维护自己的就绪队列来存放待执行的线程,这样可以减少多核间的竞争,提高调度效率。当线程需要被调度执行时,它会被放入就绪队列中等待CPU分配执行时间。线程的执行流程如下:

  1. CPU从就绪队列中选择一个线程
  2. 加载线程的上下文到CPU寄存器
  3. 执行线程指令,如果涉及函数调用则将函数信息压入线程栈中
  4. 将执行结果写回内存
  5. 收到中断信号时,保存线程上下文并将其放入适当的队列(等待队列或就绪队列)
  6. 当线程再次可执行时,将其放回就绪队列等待调度

需要注意的是,操作系统为了提高效率,会将处于休眠状态或因锁而阻塞的线程提前挂起并放入等待队列。当I/O操作完成或其他等待条件满足时,通过中断通知将线程重新放回就绪队列。此外,高优先级的线程可以抢占低优先级线程的执行权:

# 进程的创建与状态转换

在Linux中,进程通常通过fork()系统调用创建。fork()会创建一个与父进程完全相同的子进程,包括代码、数据和打开的文件描述符。子进程从fork()调用点开始执行,通过返回值区分父子进程(父进程返回子进程PID,子进程返回0)。

在执行fork()后,通常会紧接着调用exec()系列函数之一来加载新的程序映像到子进程的内存空间。除了fork(),Linux还提供了vfork()用于更高效的进程创建,以及clone()系统调用用于创建线程或轻量级进程。

进程在其生命周期中会经历多种状态:

  • 运行态(Running):进程正在CPU上执行或等待CPU分配
  • 就绪态(Ready):进程具备运行条件但未获得CPU时间
  • 阻塞态(Blocked/Waiting):进程等待某个事件(如I/O完成、信号等)而无法运行
  • 停止态(Stopped):进程被信号(如SIGSTOP)暂停执行
  • 僵尸态(Zombie):进程已结束但父进程尚未调用wait()回收其资源

# 线程同步机制

多线程环境下,多个线程访问共享资源时需要进行同步控制,以避免竞态条件(Race Condition)和数据不一致问题。常见的线程同步机制包括:

  • 互斥锁(Mutex):确保同一时间只有一个线程能访问临界区
  • 信号量(Semaphore):控制对有限资源的访问数量
  • 条件变量(Condition Variable):线程间的协调机制,允许线程等待特定条件
  • 读写锁(Read-Write Lock):允许多个线程同时读取,但写入时独占访问

# 进程间通信(IPC)

进程间通信是多进程协作的基础,主要方式包括:

  • 管道(Pipe)和命名管道(FIFO)
  • 消息队列(Message Queue)
  • 共享内存(Shared Memory)
  • 信号量(Semaphore)
  • 套接字(Socket)
  • 信号(Signal)

Linux中每个进程都有独立的虚拟地址空间,因此需要使用IPC机制来实现进程间的数据交换。

# 小结

本文从进程的基本概念入手,探讨了进程的内存管理机制和调度算法,同时通过分析进程的重量级特性和单执行流的局限性,引出了多线程的设计理念和CPU调度策略。我们还介绍了进程创建、状态转换、线程同步以及进程间通信等高级概念。理解进程和线程的本质区别对于编写高效的并发程序具有重要意义。

通过本文的学习,你应该能够:

  • 理解进程和线程在操作系统中的不同角色和关系
  • 掌握虚拟内存和MMU的工作原理
  • 了解进程内存空间的组成结构
  • 理解现代操作系统的调度算法
  • 掌握Linux中task_struct结构体的基本概念
  • 了解进程创建和状态转换机制
  • 理解线程同步和进程间通信的重要性

我是 SharkChili ,Java 开发者,Java Guide 开源项目维护者。欢迎关注我的公众号:写代码的SharkChili,也欢迎您了解我的开源项目 mini-redis:https://github.com/shark-ctrl/mini-redis。

为方便与读者交流,现已创建读者群。关注上方公众号获取我的联系方式,添加时备注加群即可加入。

# 参考

《趣话计算机底层技术》

编辑 (opens new window)
上次更新: 2026/03/26, 01:05:31
Linux线程管理
Linux进程间通信机制

← Linux线程管理 Linux进程间通信机制→

最近更新
01
基于EasyExcel实现高效导出
03-25
02
从开源框架中学习那些实用的位运算技巧
03-25
03
浅谈分布式架构设计思想和常见优化手段
03-25
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×