需求:A线程会修改T类型的变量x,B线程要读取x,由于x很大,B读取和操作的时候需要加锁,这样会占用很长的x的时间。
解决办法:
方法1:
B线程先加锁拷贝x到x_copy,然后锁可以释放,后面操作x_copy。但是拷贝也是很耗时的;
std::mutex mtx; T x; // 假设T是需要保护的大对象 // B线程读取逻辑 T x_copy; { std::lock_guard<std::mutex> lock(mtx); x_copy = x; // 拷贝x到x_copy } // 后续操作x_copy(无需加锁)方法2:
不要维护x,维护std::shared_ptr<const T> x_ptr。然后B线程加锁复制 x_ptr_copy = x_ptr (只是创建了shared_ptr新增计数,没有发生拷贝),然后锁可以释放,B线程后续读取x_ptr_copy时读的是旧内容,即使此时x_ptr被A线程改变了,也不影响B的旧内容。
std::mutex mtx; std::shared_ptr<const T> x_ptr = std::make_shared<T>(); // A线程修改逻辑 { std::lock_guard<std::mutex> lock(mtx); auto new_ptr = std::make_shared<T>(*x_ptr); // 深拷贝 // 修改new_ptr指向的对象... x_ptr = std::move(new_ptr); // 原子替换 } // B线程读取逻辑 std::shared_ptr<const T> x_ptr_copy; { std::lock_guard<std::mutex> lock(mtx); x_ptr_copy = x_ptr; // 仅增加引用计数 } // 后续操作x_ptr_copy(无需加锁)注意,这里用std::shared_ptr<const T>里的const非常重要,它保证了x_ptr的对象内容不会改变。想修改x_ptr只能整体替换指针指向对象,而不能改变当前指向对象的具体内容。