当前位置: 首页 > news >正文

进程与线程的根本区别

在 Linux 中,进程和线程的根本区别在于:资源管理方式隔离程度

简单来说:

  • 进程是资源分配的基本单位。每个进程都拥有独立的、完整的资源集合。

  • 线程是 CPU 调度的基本单位。它是进程的一个执行流,与同进程下的其他线程共享绝大部分资源。

详细对比表

特性进程线程说明与比喻
根本区别资源拥有的基本单位CPU 调度的基本单位进程是“公司”,拥有办公室、打印机等资源(内存、文件);线程是“员工”,共享公司资源,但各自执行任务。
资源隔离高。拥有独立的地址空间、数据栈、文件描述符表等。低。共享同一进程的地址空间、文件描述符、全局变量等。一个进程崩溃不会影响其他进程。一个线程崩溃通常会导致整个进程及其所有线程崩溃。
内存空间独立的虚拟地址空间。共享其所属进程的虚拟地址空间。进程间通信 (IPC) 需要特殊机制(如管道、消息队列、共享内存)。线程间通信非常简单,直接读写全局变量即可。
创建开销大。需要分配独立的内存空间、建立众多的数据结构(如页表)。小。只需分配自己的栈和少量寄存器状态,共享已有资源。fork() 一个进程比 pthread_create() 创建一个线程慢得多。
上下文切换开销大。需要切换虚拟地址空间(刷新 TLB 缓存)。开销小。只需切换栈和寄存器状态,地址空间不变。线程切换更快,效率更高。
数据共享复杂,需要通过进程间通信 (IPC) 机制。简单,天然共享全局变量、堆内存、文件句柄等。线程共享数据方便,但这也带来了同步问题(需用互斥锁、信号量等)。
健壮性高。一个进程崩溃,不会影响其他进程。低。一个线程崩溃(如段错误)会导致整个进程死亡,波及所有同进程线程。多进程架构更稳定,但通信成本高。
控制终端有独立的进程组、会话组概念。共享其所属进程的进程组和会话组。在终端中,Ctrl+C 会发送信号给整个进程组。

Linux实现方式

许多教科书会告诉你“进程和线程是不同的概念”,但在 Linux 的实现上,有一个关键点需要理解:

Linux 并不从内核层面严格区分进程和线程。

Linux 内核使用一种通用的模型——任务(Task)——来表示一个执行上下文。无论是我们称呼的“进程”还是“线程”,在内核里都是一个 task_struct 结构体。

那么区别是如何产生的呢?

关键在于 clone() 系统调用 的参数。

对于clone()的理解

  • 创建进程: 通过 fork()vfork() 系统调用,其底层调用 clone() 时,设置的参数共享资源很少(特别是设置了 CLONE_VM 标志,表示不共享内存地址空间)。

    • 相当于创建了一个拥有全新独立资源的 task_struct。
  • 创建线程: 通过 pthread_create() 库函数,其底层调用 clone() 时,设置的参数共享大量资源(如 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND 等),这意味着新的 task_struct共享内存空间、文件系统信息、文件描述符表和信号处理程序。

    • 相当于创建了一个共享绝大部分资源的 task_struct。

因此,在 Linux 中:

  • 进程:可以看作是一个只有一个线程的进程。

  • 线程:可以看作是共享了同一份资源的“轻量级进程”(Light-Weight Process, LWP)。

你可以使用 ps -eLf 命令来查看进程和它们内部的线程(LWP)。其中 PID 是进程 ID,而 LWP 是线程 ID。对于主线程,PIDLWP 的值是相同的。

一个生动的比喻:浏览器

打开一个浏览器(如Chrome)就是一个进程。

  • 这个进程拥有它自己的内存空间,用来存储浏览器的代码、UI界面等

然后,你在这个浏览器中:

  • 打开一个标签页访问新闻网站 -> 浏览器进程可能会创建一个线程来处理网络请求和渲染页面。

  • 打开另一个标签页播放视频 -> 又会创建另一个线程来解码视频和音频。

  • 浏览器扩展也在后台运行 -> 每个扩展可能也运行在独立的线程中。

所有这些线程共享着浏览器进程的资源,比如Cookie数据、缓存文件、用户登录状态等。它们并行工作,让你可以同时看视频、下载文件而不卡顿。

如果其中一个标签页(线程)因为访问了一个有问题的网页而崩溃了,通常整个浏览器(进程)都会崩溃,因为你所有的标签页(线程)共享着同一个内存空间。

而如果你同时打开了Chrome和Firefox,它们就是两个不同的进程。Chrome崩溃了,Firefox依然可以正常运行,因为它们的内存空间是相互隔离的

小结

场景推荐使用原因
需要高安全性和稳定性多进程故障被隔离,一个组件崩溃不会导致整个应用瘫痪。
需要频繁创建和销毁多线程创建和上下文切换的开销小,速度快。
需要大量计算(CPU密集型)多进程(或多线程+多核)可真正利用多核CPU。但若需频繁共享数据,多线程可能更优。
需要大量IO操作(IO密集型)多线程线程在等待IO时,其他线程可以继续执行,效率极高。
需要频繁共享和交换数据多线程数据共享在同一内存空间,非常简单高效。

Linux 中的进程是资源分配的容器,而线程是在这个容器内并行执行的实体线程共享容器的资源,从而实现了轻量和高效,但也牺牲了隔离性带来的稳定性。内核通过 clone() 系统调用的不同参数来灵活地实现这两种概念。

http://www.dtcms.com/a/357705.html

相关文章:

  • 【双指针 - LeetCode】42. 接雨水
  • gstreamer使用hook的简单示例
  • 用户自定义字段(Custom Fields)设计方案,兼顾多语言、分组、校验、权限、查询性能、审计与多租户
  • LeetCode - 128. 最长连续序列
  • LeetCode第二题知识点3 ----引用类型
  • lxml库如何使用
  • DSP280049 CLA可访问资源
  • 【开题答辩全过程】以 非遗信息管理系统为例,包含答辩的问题和答案
  • 2025年企业管理与经济、文化发展国际会议(MECD 2025)
  • 拎包入住搭建 Browser Use Agent:基于PPIO Model API +Agent 沙箱的一体化构建
  • React-Native项目回忆
  • QML Chart组件之坐标轴共有属性
  • 基于Springboot + vue3实现的教育资源共享平台
  • Java流程控制03——顺序结构(本文为个人学习笔记,内容整理自哔哩哔哩UP主【遇见狂神说】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
  • PCIe 6.0 TLP路由机制:解密高效数据传输的核心架构
  • 贪心算法面试常见问题分类解析
  • 了解 JavaScript 虚拟机(VM)引擎
  • 【项目思维】编程思维学习路线(推荐)
  • Simulink过程数据存储为mat
  • PHP的header()函数分析
  • Web开发工具一套式部署Maven/Nvm/Mysql/Redis
  • 迅睿CMS标签工具箱v1.1版本已更新
  • C++ STL之封装红黑树实现map/set
  • linux系统学习(15.启动管理)
  • Anaconda安装与conda使用详细版
  • 杨校老师竞赛课堂之C++语言GESP一级笔记
  • JUC并发编程09 - 内存(01) - JMM/cache
  • HITTER——让双足人形打乒乓球(且可根据球的走向移动脚步):高层模型规划器做轨迹预测和击球规划,低层RL控制器完成击球
  • windows下安装redis
  • fcitx5-rime自动部署的实现方法