如何等待互斥锁解锁且不后续锁定?反向条件变量技术问询
你的需求正好匹配读写锁的场景,C++17及以后的标准库提供了std::shared_mutex,结合std::shared_lock和std::unique_lock就能完美解决问题:
- 读取线程(包括
std::for_each(par_unseq)启动的所有子线程)使用std::shared_lock<std::shared_mutex>获取共享锁:多个读取线程可以同时持有共享锁,互相不阻塞,完全满足无写入时并行读取的需求。 - 主线程写入时使用
std::unique_lock<std::shared_mutex>获取独占锁:此时所有尝试获取共享锁的读取线程会被阻塞(操作系统层面挂起线程,不会忙循环),直到主线程释放独占锁后,读取线程才能继续执行。
代码示例
#include <shared_mutex> #include <execution> #include <algorithm> #include <vector> std::shared_mutex data_mutex; std::vector<int> shared_data; // 共享数据 // 子线程的读取+计算逻辑 void process_data() { std::for_each(std::execution::par_unseq, shared_data.begin(), shared_data.end(), [&](int& elem) { // 获取共享锁,读取数据 std::shared_lock lock(data_mutex); int value = elem; // 如果计算不需要实时访问数据,可以提前释放锁,提升并行效率 lock.unlock(); // 执行大量计算 // ... }); } // 主线程的写入逻辑 void write_data(int new_value) { // 获取独占锁,阻塞所有读取线程 std::unique_lock lock(data_mutex); // 执行写入操作 shared_data.push_back(new_value); // 锁会在作用域结束时自动释放,读取线程恢复执行 }
关键优势
- 无需预知线程数:不管
std::for_each启动多少个线程,每个线程只需独立获取共享锁即可,不需要提前协调数量。 - 无额外等待开销:没有写入操作时,读取线程完全并行,不会因为同步机制产生额外等待。
- 操作系统级阻塞:标准库的锁机制会通过操作系统调度挂起等待的线程,避免忙循环带来的CPU资源浪费。
注意事项
- 如果你的计算过程需要确保共享数据不被修改(比如计算依赖数据的连续状态),不要提前释放共享锁,让锁持有到计算完成即可。
std::execution::par_unseq允许编译器进行更激进的优化,确保锁的操作是线程安全的,不要在迭代逻辑中出现锁的嵌套或不当释放。
内容的提问来源于stack exchange,提问作者Smasheded
相关产品推荐
相关产品推荐

