1. 进程(Process)
概念(C++ 视角)
- 进程是程序的一次运行实例,拥有独立的内存空间(代码段、数据段、堆、栈)。
- C++ 程序运行后,OS 会为它创建一个进程。
- 不同进程之间内存隔离,需要 IPC(管道、共享内存、Socket 等)通信。
C++ 视角下对比进程、线程与协程的核心差异。进程拥有独立内存空间,隔离性好但创建切换开销大;线程共享进程内存,通信方便但存在线程安全问题;协程为轻量级用户态调度,适合高并发 I/O 密集型任务。文章通过代码示例展示了 fork+exec、std::thread 及 C++20 coroutine 的实现细节,并总结了三者适用场景。
| 优点 | 说明 |
|---|
| 隔离性好、稳定性高 | 一个进程崩溃不会影响其他进程 |
| 安全性好 | 内存独立,不易被非法访问 |
| 适合多核并行 | 多进程可充分利用 CPU 核心 |
| 缺点 | 说明 |
|---|---|
| 创建开销大 | 需要分配独立内存空间 |
| 切换开销大 | 进程切换需要保存大量上下文 |
| 通信复杂 | IPC 通信比线程复杂得多 |
Windows 不能用
fork(),Linux/Unix 可以。示例中父进程创建子进程,子进程执行ls命令。
#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 + execstd::thread 创建。| 优点 | 说明 |
|---|---|
| 创建开销比进程小 | 无需独立内存空间 |
| 切换比进程快 | 共享大部分资源 |
| 通信方便 | 直接共享内存即可 |
| 缺点 | 说明 |
|---|---|
| 线程安全问题严重 | 多线程共享内存 → 有竞争风险 |
| 容易死锁 | mutex、condition_variable 等用不好就会死锁 |
| 一个线程崩溃会导致整个进程崩溃 | 共享内存导致稳定性较差 |
用 C++ 标准库创建一个线程并等待其执行。
#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;
}
co_await, co_yield, co_return)。co_await 等方式让出执行权。| 优点 | 说明 |
|---|---|
| 极轻量级 | 创建成本比线程小几个数量级 |
| 切换开销非常低 | 不涉及 OS 调度 |
| 适合大量并发任务 | 比如 10 万个 socket 连接 |
| 编程模型简单 | 写法像同步代码但本质异步 |
| 缺点 | 说明 |
|---|---|
| 不是并行,只是并发 | 单线程协程不能利用多核 CPU |
| 需要协程调度器 | C++20 提供语言原语但无完整调度库 |
| 协程逻辑复杂时语义可能难理解 |
使用
std::coroutine_handle+ promise 自定义一个简单协程。实现一个'打印任务'协程,可暂停/恢复。
#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;
}
运行输出类似:
Coroutine step 1
Resume coroutine...
Coroutine step 2
Resume again...
Coroutine finished
Resume last time...
co_await、co_return| 对比项 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 内存空间 | 独立 | 共享 | 共享(在同线程内) |
| 创建开销 | 大 | 中 | 极小 |
| 切换成本 | 最大 | 中 | 极小(用户态) |
| 是否并行 | 是 | 是 | 否(除非多个线程跑协程) |
| 是否安全 | 最安全 | 最不安全 | 与线程一致 |
| 稳定性 | 高 | 中 | 中 |
| 数量级 | 少(几十) | 中(几千) | 多(10 万+) |
| 使用难度 | 中 | 高 | 中 |

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online