Linux 进程和线程到底有什么区别?一文彻底讲清楚 很多人都知道“进程是资源分配的基本单位线程是 CPU 调度的基本单位”但如果继续追问进程到底拥有哪些资源线程之间共享什么为什么线程切换更快Linux 内核又是如何实现线程的很多人就不一定能完整回答出来了。本文将从概念、内存模型、资源共享、创建方式、通信方式、上下文切换以及实际应用场景等方面系统讲清楚 Linux 中进程与线程的区别。一、先看结论可以先用一句话理解进程是资源容器强调隔离线程是进程中的执行单元强调协作生活化理解一个进程就像一套独立的房子同一个进程中的多个线程就像房子里一起工作的多个人不同房子之间彼此隔离同一套房子里的人共享客厅、厨房和物品但每个人有自己的工作状态二、什么是进程进程可以理解为程序的一次运行实例。程序本身只是存储在磁盘上的可执行文件例如/usr/bin/nginx /usr/bin/python3 /usr/bin/java当操作系统加载程序并开始执行后就会创建一个进程。例如执行python3 app.py此时磁盘上的python3是程序而正在运行的 Python 实例是进程。同一个程序可以同时启动多个进程。例如python3 app.py python3 app.py python3 app.py虽然三个进程运行的是同一份程序代码但它们拥有不同的进程 ID 和独立的运行环境。三、一个进程包含哪些内容Linux 中的一个进程通常包含以下资源。1. 进程 ID每个进程都有一个唯一的进程 ID也就是 PID。可以使用以下命令查看ps-ef或者psaux输出示例root 1024 1 0 10:20 ? 00:00:02 nginx www-data 1025 1024 0 10:20 ? 00:00:01 nginx其中1024是主进程 PID1025是工作进程 PID每个进程都有自己独立的编号2. 虚拟地址空间每个进程都拥有自己的虚拟地址空间。典型的进程地址空间包括高地址 ┌──────────────────┐ │ 栈 │ ├──────────────────┤ │ │ │ 内存映射区域 │ │ │ ├──────────────────┤ │ 堆 │ ├──────────────────┤ │ 数据段 │ ├──────────────────┤ │ 代码段 │ └──────────────────┘ 低地址各区域作用如下。代码段代码段保存程序执行的机器指令。例如下面的函数代码intadd(inta,intb){returnab;}编译后对应的机器指令通常存放在代码段中。代码段一般具有只读和可执行属性。数据段数据段主要保存已经初始化的全局变量和静态变量。intglobal_value100;staticintcount10;BSS 段BSS 段主要保存未初始化或初始化为零的全局变量和静态变量。intglobal_count;staticintstatus;堆堆主要用于动态内存分配。int*datamalloc(sizeof(int)*100);在 C 中使用new申请的对象通常也存放在堆中。User*usernewUser();栈栈主要保存函数参数局部变量函数返回地址部分寄存器信息函数调用上下文例如voidtest(){intnumber10;}局部变量number通常存放在线程栈中。3. 文件描述符进程打开文件、网络连接、管道或设备后Linux 会为其分配文件描述符。常见文件描述符0标准输入 stdin 1标准输出 stdout 2标准错误 stderr例如intfdopen(data.txt,O_RDONLY);fd就是文件描述符。需要注意的是文件描述符只是进程内部的一个整数索引真正的文件对象由内核维护。4. 信号处理方式Linux 使用信号通知进程发生了某些事件。常见信号SIGINT 用户按下 CtrlC SIGTERM 请求进程正常退出 SIGKILL 强制终止进程 SIGSEGV 非法内存访问 SIGCHLD 子进程状态发生变化发送信号kill-151234强制终止进程kill-91234其中1234是目标进程的 PID。5. 用户和权限信息每个进程都有对应的用户和用户组信息例如实际用户 ID有效用户 ID实际组 ID有效组 ID附加组信息这些信息决定进程可以访问哪些文件、设备和系统资源。6. 调度信息Linux 内核还会维护进程或线程的调度信息例如当前运行状态调度策略优先级CPU 时间当前运行的 CPU 核心上下文信息四、什么是线程线程可以理解为进程内部的一条执行流。一个进程至少包含一个线程也就是主线程。如果一个进程创建了更多线程那么这些线程可以在同一个进程中并发执行不同任务。例如一个网络服务器可能包含主线程接收客户端连接 线程 1处理客户端 A 请求 线程 2处理客户端 B 请求 线程 3执行日志写入 线程 4执行定时任务这些线程属于同一个进程共享进程的大部分资源。五、线程拥有自己的哪些资源同一个进程中的线程虽然会共享大量资源但每个线程也有自己的私有执行上下文。1. 线程 ID每个线程都有自己的线程 ID。在 POSIX 线程库中可以使用pthread_self();获取当前线程标识。在 Linux 内核层面每个可调度任务都有对应的任务 ID。2. 程序计数器程序计数器记录线程下一条需要执行的指令地址。不同线程可能执行不同函数因此每个线程必须拥有自己的程序计数器。3. 寄存器上下文CPU 在执行线程时会使用多个寄存器保存计算状态。当线程被切换出去时内核需要保存它的寄存器信息当线程再次运行时再恢复这些寄存器信息。4. 线程栈每个线程都有自己独立的栈。例如void*worker(void*arg){intcount100;charbuffer[1024];returnNULL;}count和buffer是线程函数中的局部变量通常存放在当前线程的栈中。多个线程不能共用同一个栈否则不同函数调用之间会发生严重冲突。5. 调度状态和优先级每个线程都可以被独立调度因此不同线程可能处于不同状态一个线程正在 CPU 上运行一个线程正在等待网络数据一个线程正在等待互斥锁一个线程正在休眠六、同一个进程中的线程共享什么同一进程中的线程通常共享以下资源。1. 代码段所有线程执行的是同一进程中的程序代码。不同线程可以执行相同函数也可以执行不同函数。2. 数据段全局变量和静态变量通常由同一进程中的所有线程共享。例如intglobal_count0;多个线程都可以访问和修改global_count。这也会带来线程安全问题。例如两个线程同时执行global_count;最终结果可能不是预期值因为global_count并不是一个不可分割的原子操作。3. 堆内存通过malloc或new申请的堆内存通常可以被同一进程中的多个线程访问。int*shared_datamalloc(sizeof(int)*100);只要其他线程获得了shared_data的地址就可以访问这块内存。4. 打开的文件同一进程中的线程共享文件描述符表。如果一个线程打开文件intfdopen(log.txt,O_WRONLY);其他线程通常也可以使用同一个fd写入文件。5. 当前工作目录同一进程中的线程通常共享当前工作目录。如果一个线程调用chdir(/tmp);可能会影响同一进程中的其他线程。6. 信号处理方式同一进程中的线程通常共享信号处理函数但每个线程可以有自己的信号屏蔽集合。七、进程和线程的核心区别对比项进程线程基本定义程序的一次运行实例进程中的一条执行流资源关系拥有相对独立的资源共享所属进程的大部分资源地址空间不同进程地址空间相互隔离同一进程内线程共享地址空间CPU 调度Linux 实际调度可执行任务线程是常见的调度执行单位创建开销相对较大相对较小切换开销通常相对较大通常相对较小通信方式管道、消息队列、共享内存、Socket 等直接访问共享内存数据安全隔离性较好容易发生数据竞争稳定性一个进程崩溃通常不直接影响其他进程一个线程崩溃可能导致整个进程退出适用场景服务隔离、独立任务、安全边界高并发、任务协作、共享数据需要注意“进程是资源分配的基本单位线程是 CPU 调度的基本单位”是一种便于理解的操作系统概念总结。在 Linux 内核中进程和线程的底层实现非常接近。它们都可以使用内核中的任务结构进行描述主要区别在于彼此之间共享了哪些资源。八、为什么线程比进程更轻量线程通常被称为轻量级执行单元主要有以下几个原因。1. 创建线程时共享现有资源创建新进程时需要建立相对独立的进程运行环境。创建线程时可以直接共享当前进程的地址空间代码段数据段堆文件描述符大部分系统资源因此创建线程通常比创建进程更轻量。2. 线程通信更直接同一进程中的线程可以直接通过共享变量通信。inttask_count0;不同线程可以直接访问task_count。而不同进程不能直接访问彼此的普通内存需要使用进程间通信机制。3. 上下文切换成本通常更低进程切换时往往涉及更多地址空间和内存映射相关状态的切换。线程切换时如果两个线程属于同一个进程它们共享地址空间因此需要切换的资源通常更少。不过线程切换仍然不是免费的仍然需要保存和恢复CPU 寄存器程序计数器栈指针调度状态其他执行上下文线程数量也不是越多越好。九、进程是如何创建的Linux 中常见的进程创建方式是fork()。1. 使用 fork 创建子进程#includestdio.h#includeunistd.hintmain(){pid_tpidfork();if(pid0){perror(fork);return1;}if(pid0){printf(我是子进程PID%d\n,getpid());}else{printf(我是父进程PID%d子进程 PID%d\n,getpid(),pid);}return0;}fork()调用成功后会出现两个执行流父进程中的fork()返回子进程 PID子进程中的fork()返回 02. 使用 exec 执行新程序fork()创建子进程后通常会调用exec系列函数加载新程序。#includeunistd.h#includestdio.hintmain(){execl(/bin/ls,ls,-l,NULL);perror(execl);return1;}exec不会再创建一个新的进程而是使用新程序替换当前进程的代码和数据。常见组合fork 创建子进程 ↓ 子进程调用 exec ↓ 子进程执行新的程序Shell 执行命令时经常使用类似机制。十、线程是如何创建的Linux 用户空间程序通常使用 POSIX Threads也就是 pthread。1. pthread_create 创建线程#includestdio.h#includepthread.hvoid*worker(void*arg){constchar*name(constchar*)arg;printf(线程开始执行%s\n,name);returnNULL;}intmain(){pthread_tthread;intresultpthread_create(thread,NULL,worker,worker-1);if(result!0){printf(线程创建失败\n);return1;}pthread_join(thread,NULL);printf(主线程结束\n);return0;}编译命令gcc thread_demo.c-othread_demo-pthread运行./thread_demo2. pthread_join 等待线程结束pthread_join(thread,NULL);该函数会阻塞当前线程直到目标线程执行结束。它的作用类似于等待子进程结束但它等待的是线程。3. pthread_exit 退出线程线程可以主动调用pthread_exit(NULL);结束当前线程。它只结束当前线程不一定会结束整个进程。但是如果主线程直接从main返回整个进程通常会结束其他线程也会被终止。十一、线程为什么容易出现安全问题多线程最常见的问题是数据竞争。假设多个线程共享一个全局变量intcount0;两个线程都执行count;表面上看只是一条语句但底层可能分为1. 从内存读取 count 2. 对 count 加 1 3. 将新值写回内存可能出现以下执行顺序线程 A 读取 count值为 10 线程 B 读取 count值为 10 线程 A 写入 11 线程 B 写入 11执行了两次加一结果却只增加了一次。这就是典型的数据竞争。十二、使用互斥锁保护共享数据可以使用互斥锁确保同一时刻只有一个线程访问临界区。#includestdio.h#includepthread.h#defineLOOP_COUNT100000intcount0;pthread_mutex_tmutexPTHREAD_MUTEX_INITIALIZER;void*worker(void*arg){for(inti0;iLOOP_COUNT;i){pthread_mutex_lock(mutex);count;pthread_mutex_unlock(mutex);}returnNULL;}intmain(){pthread_tthread1;pthread_tthread2;pthread_create(thread1,NULL,worker,NULL);pthread_create(thread2,NULL,worker,NULL);pthread_join(thread1,NULL);pthread_join(thread2,NULL);printf(count %d\n,count);pthread_mutex_destroy(mutex);return0;}理论输出count 200000互斥锁保护的代码区域称为临界区。需要注意锁的范围不应该过大否则会降低程序并发能力。十三、进程之间如何通信不同进程拥有相互隔离的虚拟地址空间不能直接访问对方的普通变量。因此需要使用 IPC也就是进程间通信机制。常见 IPC 方式包括1. 管道父进程 → 管道 → 子进程适合具有亲缘关系的进程进行简单通信。Shell 中的管道psaux|grepnginxps aux的输出会通过管道传给grep nginx。2. 命名管道命名管道也叫 FIFO。mkfifomessage_pipe不同进程可以通过指定的 FIFO 文件通信。3. 消息队列消息队列允许进程按照消息结构发送和接收数据。适合异步通信。4. 共享内存共享内存允许多个进程映射同一块物理内存。它通常是非常高效的 IPC 方式。但是多个进程同时访问共享内存时也需要配合信号量互斥锁文件锁原子操作否则同样可能发生数据竞争。5. SocketSocket 不仅可以用于不同计算机之间的网络通信也可以用于同一台计算机中的进程通信。常见方式TCP Socket UDP Socket Unix Domain SocketUnix Domain Socket 在本机进程通信中非常常见例如 Docker、MySQL 和很多后台服务都会使用。6. 信号信号主要用于事件通知。例如kill-TERM1234向进程发送终止请求。信号适合传递事件不适合传输大量业务数据。十四、线程之间如何通信同一进程中的线程共享地址空间因此线程之间可以直接使用共享变量通信。例如inttask_ready0;一个线程修改task_ready1;另一个线程读取if(task_ready){// 开始处理任务}但直接使用共享变量可能出现数据竞争内存可见性问题指令重排序问题死锁活锁饥饿因此通常需要配合同步机制互斥锁 mutex 读写锁 rwlock 条件变量 condition variable 信号量 semaphore 自旋锁 spinlock 原子操作 atomic 屏障 barrier十五、进程和线程的上下文切换操作系统为了让多个任务共享 CPU会不断切换正在运行的任务。这个过程称为上下文切换。进程切换可能涉及保存当前 CPU 寄存器保存程序计数器保存栈指针切换调度状态切换地址空间相关信息切换页表相关上下文重新建立部分缓存状态线程切换可能涉及保存和恢复寄存器保存和恢复程序计数器保存和恢复栈指针切换调度状态切换线程局部数据如果切换的两个线程属于同一个进程它们共享地址空间因此通常不需要完整切换地址空间。这也是线程切换一般比进程切换更轻量的原因之一。但需要注意切换成本与操作系统实现、CPU 架构、缓存状态、线程所属进程以及任务工作集等因素有关不能简单理解为线程切换永远比进程切换快。十六、Linux 内核中的进程和线程Linux 对进程和线程的实现方式比较特别。在 Linux 内核中进程和线程都可以看作可调度的任务。它们的核心差异主要体现在资源共享程度上。创建任务时可以通过不同参数决定是否共享地址空间文件描述符表文件系统信息信号处理方式其他资源从这个角度看进程共享资源较少的任务 线程共享资源较多的任务Linux 用户空间的pthread_create()最终会通过底层系统调用创建一个共享当前进程资源的新任务。因此Linux 中的线程也经常被称为轻量级进程。十七、如何查看 Linux 进程和线程1. 查看进程ps-ef或者psaux2. 动态查看进程top也可以使用htop3. 查看某个进程的线程ps-T-p进程PID例如ps-T-p12344. 使用 top 查看线程启动top后按H可以切换线程显示模式。也可以直接执行top-H查看指定进程中的线程top-H-p12345. 查看进程状态cat/proc/1234/status其中1234是 PID。常见字段Name State Pid PPid Threads VmSize VmRSSThreads表示当前进程包含的线程数量。6. 查看进程文件描述符ls-l/proc/1234/fd7. 查看进程内存映射cat/proc/1234/maps或者pmap1234十八、进程和线程分别适合什么场景适合使用多进程的场景1. 需要故障隔离例如浏览器的不同标签页使用不同进程。一个标签页崩溃时不希望整个浏览器一起崩溃。2. 需要安全隔离不同进程拥有独立地址空间更适合作为安全边界。3. 独立服务例如用户服务 订单服务 支付服务 日志服务不同服务可以部署为独立进程。4. CPU 密集型任务在某些语言运行时中多进程可以绕过运行时级别的线程限制。例如 Python 的 CPU 密集型任务有时会选择多进程。适合使用多线程的场景1. 网络服务器多个线程可以同时处理多个客户端连接。2. GUI 程序主线程负责界面事件工作线程负责耗时任务。3. 线程池预先创建固定数量的线程循环处理任务避免频繁创建和销毁线程。4. 数据共享频繁如果多个执行任务需要频繁共享大量数据线程通常比进程通信更方便。5. I/O 密集型任务例如网络请求磁盘读写数据库访问消息队列消费当一个线程等待 I/O 时其他线程可以继续运行。十九、实际项目中应该怎么选不能简单地说多进程一定更好或者多线程一定更快。应该根据实际需求选择。优先考虑多进程当系统更关注隔离性稳定性安全性独立部署故障不扩散可以优先考虑多进程。优先考虑多线程当系统更关注高并发快速通信数据共享较低创建成本任务协作可以优先考虑多线程。实际工程中经常组合使用很多系统采用多进程 每个进程内部多线程例如一个服务器可以启动多个工作进程每个工作进程内部再创建线程池。这样既可以获得一定的进程隔离能力又可以获得线程协作和并发处理能力。二十、常见面试题1. 进程和线程最大的区别是什么进程拥有相对独立的地址空间和资源线程共享所属进程的大部分资源。进程强调隔离线程强调协作。2. 线程共享哪些资源同一进程中的线程通常共享代码段数据段堆文件描述符当前工作目录用户和权限信息大部分信号处理配置3. 线程私有的资源有哪些每个线程通常拥有线程 ID程序计数器CPU 寄存器上下文线程栈调度状态线程局部存储部分信号屏蔽信息4. 为什么线程切换通常比进程切换快同一进程中的线程共享地址空间因此线程切换时通常不需要完整切换地址空间和页表相关上下文需要切换的资源更少。5. 多线程一定比单线程快吗不一定。线程过多可能导致频繁上下文切换锁竞争CPU 缓存失效内存消耗增加调度开销增加程序复杂度提高如果任务量很小或者任务之间存在严重锁竞争多线程可能比单线程更慢。6. 一个线程崩溃会影响整个进程吗有可能。线程共享进程地址空间如果某个线程发生非法内存访问例如触发SIGSEGV通常可能导致整个进程终止。7. 进程间可以共享内存吗可以。虽然不同进程默认拥有独立地址空间但可以使用共享内存 IPC将同一块物理内存映射到多个进程的地址空间中。8. fork 之后父子进程内存是否完全复制从逻辑上看父子进程拥有各自独立的地址空间。但 Linux 通常使用写时复制也就是 Copy-On-Write。刚执行fork()时父子进程可以暂时共享物理内存页面。当其中一个进程尝试修改某个页面时内核才会复制该页面。这样可以减少不必要的内存复制提高fork()的效率。二十一、总结Linux 中进程与线程的核心区别可以总结为以下几点。进程是程序的一次运行实例拥有相对独立的地址空间是系统资源的容器隔离性和稳定性较好创建和切换开销通常较大进程之间需要通过 IPC 通信线程是进程中的执行流是 CPU 调度的重要执行单位共享所属进程的大部分资源每个线程拥有独立的栈和寄存器上下文创建和切换开销通常较小线程之间通信方便但需要处理同步问题最后用一句话总结进程重隔离线程重协作进程是资源容器线程是执行单元。在实际开发中不应该机械地选择多进程或多线程而应该综合考虑系统稳定性故障隔离并发规模数据共享频率通信成本开发复杂度运行环境和语言特性理解进程和线程不只是为了应付面试更是为了正确设计高并发服务器、线程池、任务调度系统、微服务以及后台程序。参考命令汇总# 查看进程ps-efpsaux# 动态查看进程tophtop# 查看线程ps-T-pPIDtop-Htop-H-pPID# 查看进程状态cat/proc/PID/status# 查看文件描述符ls-l/proc/PID/fd# 查看内存映射cat/proc/PID/maps pmap PID# 给进程发送信号kill-15PID# 强制结束进程kill-9PID推荐标签Linux 操作系统 进程 线程 多线程 并发编程 Linux内核 后端开发 程序员面试 C语言

相关新闻

最新新闻

利用邮件客户端解析差异绕过SPF:从Sender与From字段的博弈说起

利用邮件客户端解析差异绕过SPF:从Sender与From字段的博弈说起

1. 邮件安全的基础博弈:Sender与From字段的差异 当你收到一封显示为"系统管理员"发来的密码重置邮件时,第一反应是什么?大多数人会直接点击邮件中的链接——这正是钓鱼攻击者最希望看到的结果。但你可能不知道,邮件客户…

2026/7/16 3:50:26
单链表的指定结点的 插入 (前插和后插)操作

单链表的指定结点的 插入 (前插和后插)操作

文章目录指定结点的 后插 操作代码指定结点的 前插 操作代码解释 前插与后插物理结构与逻辑结构物理结构&#xff08;存储结构&#xff09;逻辑结构&#xff08;逻辑关系&#xff09;指定结点的 后插 操作代码 #include<stdio.h> #include<stdlib.h> typedef stru…

2026/7/16 3:50:26
电子招投标实务指南:系统架构、操作流程与关键注意事项

电子招投标实务指南:系统架构、操作流程与关键注意事项

一、电子招投标的定义与发展趋势电子招标投标活动&#xff0c;是指以数据电文形式&#xff0c;依托电子招标投标系统完成的全部或者部分招标投标交易、公共服务和行政监督活动。理解电子招投标需要把握几个关键点。首先&#xff0c;它依据现行招标投标法律法规开展&#xff0c;…

2026/7/16 3:50:26
京东开发岗面试题目

京东开发岗面试题目

如果你准备投 京东 的开发岗&#xff0c;最容易踩的坑通常不是不会刷题&#xff0c;而是准备方向不对。 有些公司看起来都在招开发&#xff0c;但真正进面后会发现&#xff0c;关注点完全不一样&#xff1a; 有的公司更看重高并发和分布式 有的公司更看重 C、系统基础和性能优…

2026/7/16 3:50:26
在现有 Ceph 集群搭建 S3 对象存储

在现有 Ceph 集群搭建 S3 对象存储

ceph集群搭建&#xff1a;ceph集群搭建-CSDN博客 一、在 Dashboard 创建 RGW 服务&#xff08;核心&#xff0c;开启 S3 能力&#xff09; 创建完成回到 Services 列表&#xff0c;看到 rgw 行「正在运行」列显示 3/3 即部署完成 补充命令行备用&#xff08;界面异常时用&…

2026/7/16 3:50:26
好的开放式耳机品牌有哪些?盘点26年公认口碑很好的开放式耳机

好的开放式耳机品牌有哪些?盘点26年公认口碑很好的开放式耳机

近几年开放式耳机越来越受欢迎&#xff0c;人气也一路上升&#xff0c;无论是通勤路上还是健身&#xff0c;甚至是办公都可以看到有人佩戴。行业风口之下&#xff0c;也导致有不少原本主营其他品类的品牌也开始跟风&#xff0c;行业品牌数量的增加也导致产品品质开始变得参差不…

2026/7/16 3:45:26

月新闻