返回文章索引

C++ 每日一题:进程与线程之间有什么区别?

用一问一答的方式,比较进程和线程的资源、地址空间、调度与通信方式,并说明 C++ 开发中的选择。

GitHub 原文

问:进程与线程之间有什么区别?C++ 项目中应该怎么选?

一句话概括:进程是资源分配和隔离的基本单位,线程是 CPU 调度和执行的基本单位。 一个进程至少包含一个线程,同一进程中的线程共享进程资源,但各自拥有独立的栈和寄存器上下文。

对比项 进程 线程
地址空间 通常拥有独立的虚拟地址空间 共享所属进程的地址空间
资源 独立管理文件描述符、堆、全局数据等资源 共享进程资源,拥有自己的栈、寄存器和线程局部存储
创建与切换 创建、切换和销毁的成本通常更高 成本通常更低,但仍可能产生调度和缓存开销
通信 需要管道、Socket、共享内存等进程间通信机制 可以直接读写共享内存,但必须使用锁、原子操作等同步手段
隔离性 一个进程崩溃通常不会直接破坏另一个进程的地址空间 一个线程越界或未定义行为可能拖垮整个进程
典型用途 服务隔离、权限隔离、故障域隔离 并行计算、异步任务、共享状态的并发处理

为什么线程共享资源仍然需要同步?

共享地址空间只解决了“能不能看见同一份数据”,没有解决“多个执行流同时修改数据是否正确”。例如下面的自增操作不是一个不可分割的动作:

int counter = 0;
// 两个线程同时执行 counter++ 可能发生数据竞争

在 C++ 中,未同步的并发读写会产生数据竞争,结果属于未定义行为。可以使用 std::mutex 保护临界区,或者在适合的场景使用 std::atomic<int>

#include <atomic>
#include <thread>

std::atomic<int> counter{0};

void add_one()
{
    ++counter;
}

int main()
{
    std::thread first(add_one);
    std::thread second(add_one);
    first.join();
    second.join();
}

选择建议

  • 需要强隔离、独立升级或一个组件崩溃不能影响主服务时,优先考虑多进程。
  • 需要共享内存、降低通信成本或并行执行任务时,可以使用多线程,但要先设计好所有权、同步和退出策略。
  • 多线程不是“免费并行”:线程数过多会增加上下文切换、锁竞争和缓存失效。I/O 密集型任务与 CPU 密集型任务也应分别评估。

因此,面试回答不能只说“线程比进程轻量”。更完整的答案应该同时说明:线程共享资源所以通信方便,也因为共享资源而更容易产生数据竞争;进程隔离更强,但通信和创建的成本通常更高。