C++并发编程的最佳实践
使用现代C++标准库工具
C++11及后续版本提供了丰富的并发编程工具,包括<thread>、<mutex>、<atomic>和<future>等头文件。优先使用std::thread而非平台相关API,使用std::mutex配合std::lock_guard或std::unique_lock实现资源同步。
避免原始锁的暴露
通过RAII机制管理锁资源,确保异常安全。std::lock_guard在构造时自动加锁,析构时自动解锁;std::unique_lock提供更灵活的锁定控制。例如:
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
// 临界区代码
} // 自动解锁
善用原子操作
对于简单的计数器或标志位,使用std::atomic避免锁开销。原子操作提供无锁编程支持,例如:
std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed);
任务并行替代线程管理
使用更高层次的std::async和std::future抽象任务并行。这允许运行时系统管理线程池,而非手动创建线程:
auto future = std::async(std::launch::async, []{
return compute_heavy_task();
});
auto result = future.get();
注意内存顺序
理解内存模型和内存序(std::memory_order)。默认使用std::memory_order_seq_cst保证顺序一致性,但在性能关键场景可考虑更宽松的排序:
std::atomic<bool> ready{false};
// 写端
ready.store(true, std::memory_order_release);
// 读端
while(!ready.load(std::memory_order_acquire));
避免死锁
按固定顺序获取多个锁,或使用std::lock同时锁定多个互斥量。C++17的std::scoped_lock支持多锁RAII管理:
std::mutex mtx1, mtx2;
{
std::scoped_lock lock(mtx1, mtx2); // 自动解决死锁风险
// 操作共享资源
}
使用条件变量正确
std::condition_variable需配合谓词使用,防止虚假唤醒。示例模式:
std::condition_variable cv;
std::mutex mtx;
bool data_ready = false;
// 等待端
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return data_ready; });
}
// 通知端
{
std::lock_guard<std::mutex> lock(mtx);
data_ready = true;
}
cv.notify_one();
线程局部存储
对于不需要共享的数据,使用thread_local关键字或std::thread::id识别线程。这能避免同步开销:
thread_local int thread_specific_data = 0;
限制线程数量
通过std::thread::hardware_concurrency()获取硬件支持的线程数,避免过度订阅。线程池实现应基于工作窃取(work-stealing)等高效调度策略。
异常处理
确保线程函数内部的异常被捕获处理,否则可能导致程序终止。可通过std::promise传递异常到主线程:
std::promise<void> prom;
auto future = prom.get_future();
std::thread([&prom]{
try {
// 可能抛出异常的操作
prom.set_value();
} catch(...) {
prom.set_exception(std::current_exception());
}
}).detach();
try {
future.get();
} catch(const std::exception& e) {
// 处理异常
}
更多推荐


所有评论(0)