C++并发编程实战:同步并发操作详解

C++并发编程实战:同步并发操作详解

【免费下载链接】Cpp_Concurrency_In_Action 【免费下载链接】Cpp_Concurrency_In_Action 项目地址: https://gitcode.com/gh_mirrors/cp/Cpp_Concurrency_In_Action

引言

在多线程编程中,数据保护只是基础需求,线程间的同步操作同样至关重要。本文将深入探讨C++标准库提供的同步机制,帮助开发者掌握线程间协调的核心技术。

等待事件的实现方式

传统方式的局限性

初学者常采用轮询共享标志位的方式实现线程同步,例如:

while(!task_completed) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

这种方式存在明显缺陷:

  1. 资源浪费:线程在等待期间持续消耗CPU资源
  2. 响应延迟:无法立即感知状态变化
  3. 潜在的竞态条件

条件变量的正确使用

C++标准库提供了std::condition_variable来解决这些问题:

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

// 等待线程
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, []{return ready;});

// 通知线程
{
    std::lock_guard<std::mutex> lck(mtx);
    ready = true;
}
cv.notify_one();

关键要点:

  • 必须与互斥量配合使用
  • 使用wait的重载版本避免虚假唤醒
  • 通知前必须先修改条件变量

一次性事件处理:Future/Promise模型

基本概念

C++11引入了std::futurestd::promise来处理一次性事件:

  • promise:承诺提供结果的对象
  • future:获取承诺结果的句柄

典型应用场景

std::promise<int> result_promise;
std::future<int> result_future = result_promise.get_future();

std::thread t([&]{
    // 长时间计算
    result_promise.set_value(42); 
});

// 主线程可以继续其他工作
int result = result_future.get(); // 阻塞直到结果就绪
t.join();

异常处理

promise也可以传递异常:

try {
    // 可能抛出异常的操作
} catch(...) {
    result_promise.set_exception(std::current_exception());
}

超时处理机制

时间点与时间段

C++提供了两种时间表示方式:

  1. 时间段:std::chrono::duration
  2. 时间点:std::chrono::time_point

带超时的等待操作

std::future<int> f = std::async(some_task);

// 等待最多35毫秒
if(f.wait_for(std::chrono::milliseconds(35)) == std::future_status::ready) {
    // 任务完成
} else {
    // 超时处理
}

高级同步模式

屏障(Barrier)

C++20引入了std::barrier,允许多个线程在某个点同步:

std::barrier sync_point(3); // 等待3个线程

std::thread t1([&]{
    // 工作代码
    sync_point.arrive_and_wait();
});

std::thread t2([&]{
    // 工作代码
    sync_point.arrive_and_wait();
});

// 主线程
sync_point.arrive_and_wait();

信号量(Semaphore)

C++20的std::counting_semaphore提供了更灵活的同步控制:

std::counting_semaphore<10> sem(3); // 最大10,初始3

sem.acquire(); // 获取信号量
// 临界区操作
sem.release(); // 释放信号量

性能优化建议

  1. 减少锁粒度:尽量缩小临界区范围
  2. 避免锁竞争:使用读写锁(std::shared_mutex)替代互斥锁
  3. 无锁编程:在适当场景考虑原子操作
  4. 任务窃取:使用工作队列平衡负载

常见陷阱与解决方案

  1. 死锁

    • 总是以固定顺序获取多个锁
    • 使用std::lockstd::scoped_lock(C++17)
  2. 虚假唤醒

    • 总是使用谓词检查条件
    • 避免简单的while(!condition)循环
  3. 优先级反转

    • 合理设置线程优先级
    • 使用优先级继承协议

总结

C++标准库提供了丰富的同步原语,从基本的互斥量到高级的future/promise模型,开发者应根据具体场景选择合适的工具。理解这些同步机制的工作原理和适用场景,是构建高效、可靠并发系统的关键。

通过本文介绍的技术,开发者可以:

  • 实现线程间的高效协调
  • 处理一次性异步事件
  • 控制并发操作的执行时序
  • 构建复杂的同步模式

掌握这些同步技术将显著提升多线程程序的性能和可靠性。

【免费下载链接】Cpp_Concurrency_In_Action 【免费下载链接】Cpp_Concurrency_In_Action 项目地址: https://gitcode.com/gh_mirrors/cp/Cpp_Concurrency_In_Action

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值