✅ 1. 进程(Process)
✔ 概念(C++ 视角)
-
进程是程序的一次运行实例 ,拥有独立的内存空间(代码段、数据段、堆、栈)。
-
C++ 程序运行后,OS 会为它创建一个进程。
-
不同进程之间内存隔离,需要 IPC(管道、共享内存、Socket 等)通信。
✔ 优点
| 优点 | 说明 |
|---|---|
| 隔离性好、稳定性高 | 一个进程崩溃不会影响其他进程 |
| 安全性好 | 内存独立,不易被非法访问 |
| 适合多核并行 | 多进程可充分利用 CPU 核心 |
✔ 缺点
| 缺点 | 说明 |
|---|---|
| 创建开销大 | 需要分配独立内存空间 |
| 切换开销大 | 进程切换需要保存大量上下文 |
| 通信复杂 | IPC 通信比线程复杂得多 |
✔ 应用场景
-
Chrome 浏览器多进程架构(保证一个 Tab 崩溃不影响其它)
-
后端服务拆成多个微服务(隔离性高)
-
高安全、高可靠场景(银行、支付模块)
✅ 1. 进程示例(fork + exec,Linux)
Windows 不能用
fork(),Linux/Unix 可以。示例中父进程创建子进程,子进程执行
ls命令。
cpp
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
std::cerr << "Fork failed\n";
return 1;
}
if (pid == 0) {
// 子进程
std::cout << "Child process PID: " << getpid() << "\n";
execlp("ls", "ls", "-l", NULL); // 执行 ls -l
} else {
// 父进程
std::cout << "Parent process PID: " << getpid() << "\n";
wait(NULL); // 等待子进程结束
std::cout << "Child process finished.\n";
}
return 0;
}
✔ 展示了:
-
父进程/子进程地址空间独立
-
fork + exec -
进程阻塞等待子进程完成
✅ 2. 线程(Thread)
✔ 概念(C++ 视角)
-
线程是进程中的最小执行单位。
-
C++ 中可用
std::thread创建。 -
同一进程内的线程共享内存(代码段、堆),但有自己的栈。
✔ 优点
| 优点 | 说明 |
|---|---|
| 创建开销比进程小 | 无需独立内存空间 |
| 切换比进程快 | 共享大部分资源 |
| 通信方便 | 直接共享内存即可 |
✔ 缺点
| 缺点 | 说明 |
|---|---|
| 线程安全问题严重 | 多线程共享内存 → 有竞争风险 |
| 容易死锁 | mutex、condition_variable 等用不好就会死锁 |
| 一个线程崩溃会导致整个进程崩溃 | 共享内存导致稳定性较差 |
✔ 应用场景
-
计算密集型任务:并行排序、矩阵运算(利用多核 CPU)
-
I/O 密集型任务:服务器线程池
-
后台任务:日志线程、定时任务线程
✅ 2. 线程示例(std::thread)
用 C++ 标准库创建一个线程并等待其执行。
cpp
#include <iostream>
#include <thread>
void worker(int id) {
std::cout << "Thread " << id << " is running.\n";
}
int main() {
std::thread t(worker, 1); // 创建线程
if (t.joinable()) {
t.join(); // 等待线程结束
}
std::cout << "Thread finished.\n";
return 0;
}
✔ 展示了:
-
如何创建线程
-
如何 join
-
线程共享进程数据
✅ 3. 协程(Coroutine)
✔ 概念(C++ 视角)
-
C++20 正式原生支持协程 (
co_await,co_yield,co_return)。 -
用户态调度:协程的切换在用户空间进行,不需要操作系统。
-
轻量级执行单元,数量可以达到几十万甚至百万级别。
✔ 原理简述
-
协程不会主动抢占 CPU,需要手动
co_await等方式让出执行权。 -
和线程不同:协程不是系统级调度,而是语言/库层调度。
✔ 优点
| 优点 | 说明 |
|---|---|
| 极轻量级 | 创建成本比线程小几个数量级 |
| 切换开销非常低 | 不涉及 OS 调度 |
| 适合大量并发任务 | 比如 10 万个 socket 连接 |
| 编程模型简单 | 写法像同步代码但本质异步 |
✔ 缺点
| 缺点 | 说明 |
|---|---|
| 不是并行,只是并发 | 单线程协程不能利用多核 CPU |
| 需要协程调度器 | C++20 提供语言原语但无完整调度库 |
| 协程逻辑复杂时语义可能难理解 |
✔ 应用场景
-
超高并发网络服务器(如用协程替代回调)
-
游戏引擎脚本系统(逻辑暂停/恢复很适合协程)
-
GUI 程序的异步任务
-
异步 I/O(文件读写、socket 等)
✅ 3. 协程示例(C++20 coroutine)
使用
std::coroutine_handle+ promise 自定义一个简单协程。实现一个"打印任务"协程,可暂停/恢复。
cpp
#include <iostream>
#include <coroutine>
// 协程返回对象
struct Task {
struct promise_type {
Task get_return_object() {
return Task{
std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::exit(1); }
};
std::coroutine_handle<promise_type> handle;
Task(std::coroutine_handle<promise_type> h) : handle(h) {}
~Task() { if (handle) handle.destroy(); }
};
// 一个可挂起协程
Task myCoroutine() {
std::cout << "Coroutine step 1\n";
co_await std::suspend_always{}; // 暂停
std::cout << "Coroutine step 2\n";
co_await std::suspend_always{}; // 再暂停
std::cout << "Coroutine finished\n";
}
int main() {
auto task = myCoroutine(); // 创建协程(不会立即结束)
std::cout << "Resume coroutine...\n";
task.handle.resume();
std::cout << "Resume again...\n";
task.handle.resume();
std::cout << "Resume last time...\n";
task.handle.resume();
return 0;
}
运行输出类似:
cpp
Coroutine step 1
Resume coroutine...
Coroutine step 2
Resume again...
Coroutine finished
Resume last time...
✔ 展示了:
-
协程的挂起/恢复机制
-
完全用户态,不需要线程/进程调度
-
C++20 协程语法:
co_await、co_return
🔥 4. 三者的直观对比
| 对比项 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 内存空间 | 独立 | 共享 | 共享(在同线程内) |
| 创建开销 | 大 | 中 | 极小 |
| 切换成本 | 最大 | 中 | 极小(用户态) |
| 是否并行 | 是 | 是 | 否(除非多个线程跑协程) |
| 是否安全 | 最安全 | 最不安全 | 与线程一致 |
| 稳定性 | 高 | 中 | 中 |
| 数量级 | 少(几十) | 中(几千) | 多(10 万+) |
| 使用难度 | 中 | 高 | 中 |
🔔 总结一句话
-
进程:最安全,但最重,适合隔离性强的任务
-
线程:共享内存并行执行,适合 CPU 密集任务
-
协程:超轻量级并发,适合 I/O 密集型和高并发服务器