1. 为什么我们需要并发编程?
十年前我刚接触C++时,总觉得单线程程序就能解决所有问题。直到有一次需要处理十万级的数据文件,那个卡顿的界面和长达半小时的等待时间让我彻底改变了想法。现代CPU早已进入多核时代,我的8核处理器在跑单线程程序时,其他7个核心却在悠闲地看戏——这简直是计算资源的巨大浪费。
并发编程的本质就是让程序能够"一心多用"。想象一下餐厅里的服务员:如果只有一个服务员(单线程),他必须依次处理每桌客人的点餐、上菜、结账;而有多个服务员(多线程)时,不同桌的客人就能被同时服务。在I/O密集型和计算密集型任务中,这种差异尤为明显。
我最近做的一个图像处理项目就很典型:单线程处理100张高分辨率图片需要12分钟,而改用8个线程后,时间缩短到了1分40秒。这种性能提升是实实在在的,特别是当你面对的是服务器程序或者实时系统时。
2. C++并发编程的核心武器库
2.1 标准库中的并发三剑客
C++11带来的
cpp复制#include <iostream>
#include <thread>
void hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(hello);
t.join(); // 等待线程结束
return 0;
}
但线程就像野马,需要缰绳来控制。这就是mutex(互斥锁)的用武之地:
cpp复制std::mutex mtx;
int shared_data = 0;
void increment() {
mtx.lock();
++shared_data;
mtx.unlock();
}
警告:直接使用lock()/unlock()很危险,如果临界区代码抛出异常,可能导致锁永远无法释放。RAII风格的lock_guard才是正确姿势:
cpp复制void safe_increment() {
std::lock_guard<std::mutex> lock(mtx);
++shared_data; // 自
