C++ 多线程最佳实践
外观
简介[编辑 | 编辑源代码]
C++多线程编程允许程序同时执行多个任务,是现代软件开发中提升性能的关键技术。自C++11标准引入<thread>
头文件以来,多线程支持已成为语言核心部分。本节将系统讲解线程管理、同步机制、性能优化及常见陷阱,帮助开发者编写高效且安全的并发代码。
线程基础[编辑 | 编辑源代码]
线程创建与生命周期[编辑 | 编辑源代码]
C++中线程通过std::thread
类实现,其生命周期包含以下阶段:
#include <iostream>
#include <thread>
void hello() {
std::cout << "Hello from thread!\n";
}
int main() {
std::thread t(hello); // 线程创建
t.join(); // 等待线程结束
return 0;
}
输出示例:
Hello from thread!
同步机制[编辑 | 编辑源代码]
互斥锁(Mutex)[编辑 | 编辑源代码]
使用std::mutex
保护共享资源:
#include <mutex>
std::mutex mtx;
int shared_data = 0;
void increment() {
mtx.lock();
++shared_data; // 临界区
mtx.unlock();
}
更安全的RAII方式:
void safe_increment() {
std::lock_guard<std::mutex> lock(mtx);
++shared_data; // 自动释放锁
}
条件变量[编辑 | 编辑源代码]
实现线程间通信:
std::condition_variable cv;
bool ready = false;
void producer() {
std::this_thread::sleep_for(std::chrono::seconds(1));
ready = true;
cv.notify_one();
}
void consumer() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Data ready\n";
}
高级模式[编辑 | 编辑源代码]
线程池设计[编辑 | 编辑源代码]
避免频繁创建/销毁线程的开销:
原子操作[编辑 | 编辑源代码]
使用std::atomic
实现无锁编程:
std::atomic<int> counter(0);
void atomic_increment() {
counter.fetch_add(1, std::memory_order_relaxed);
}
内存序选项:
memory_order_seq_cst
:严格顺序一致性memory_order_release
/acquire
:同步特定操作memory_order_relaxed
:仅保证原子性
性能优化[编辑 | 编辑源代码]
伪共享(False Sharing)[编辑 | 编辑源代码]
当不同CPU核心修改同一缓存行中的不同变量时引发的性能问题:
解决方案:
struct alignas(64) PaddedData { // 64字节对齐(典型缓存行大小)
int value1;
// 填充剩余空间
char padding[64 - sizeof(int)];
};
错误处理[编辑 | 编辑源代码]
异常安全[编辑 | 编辑源代码]
线程函数中的异常必须在线程内部捕获:
void risky_task() {
try {
// 可能抛出异常的操作
} catch (...) {
std::cerr << "Thread crashed!\n";
}
}
实际案例[编辑 | 编辑源代码]
并行快速排序[编辑 | 编辑源代码]
template<typename T>
void parallel_sort(std::vector<T>& data, int threads) {
if (data.size() < 1000 || threads <= 1) {
std::sort(data.begin(), data.end());
return;
}
auto mid = data.begin() + data.size()/2;
std::thread t([&]{
parallel_sort(std::ref(data), threads/2);
});
parallel_sort(data, threads/2);
t.join();
std::inplace_merge(data.begin(), mid, data.end());
}
最佳实践总结[编辑 | 编辑源代码]
- 优先使用RAII管理资源(
lock_guard
、unique_lock
) - 最小化临界区范围
- 避免线程间共享可写数据
- 使用
thread_local
替代全局变量 - 考虑任务并行而非数据并行
- 使用高层抽象(如
std::async
)简化代码