【发布时间】:2011-07-01 14:53:46
【问题描述】:
借用 Howard Hinnant's example 并修改它以使用复制和交换,这 op= 线程安全吗?
struct A {
A() = default;
A(A const &x); // Assume implements correct locking and copying.
A& operator=(A x) {
std::lock_guard<std::mutex> lock_data (_mut);
using std::swap;
swap(_data, x._data);
return *this;
}
private:
mutable std::mutex _mut;
std::vector<double> _data;
};
我相信这是线程安全的(记住 op= 的参数是按值传递的),我能找到的唯一问题是隐藏在地毯下的问题:复制 ctor。但是,这将是一个罕见的类,它允许复制分配但不允许复制构造,因此在两种替代方案中同样存在这个问题。
鉴于自我分配是如此罕见(至少对于本示例而言),如果发生这种情况,我不介意额外的副本,因此请考虑 this != &rhs 的潜在优化可以忽略不计或悲观化。与原来的策略(下)相比,是否还有其他理由更喜欢或避免它?
A& operator=(A const &rhs) {
if (this != &rhs) {
std::unique_lock<std::mutex> lhs_lock( _mut, std::defer_lock);
std::unique_lock<std::mutex> rhs_lock(rhs._mut, std::defer_lock);
std::lock(lhs_lock, rhs_lock);
_data = rhs._data;
}
return *this;
}
顺便说一句,我认为这简洁地处理了复制ctor,至少对于这个类来说,即使它有点迟钝:
A(A const &x) : _data {(std::lock_guard<std::mutex>(x._mut), x._data)} {}
【问题讨论】:
-
An answer 提示我提出这个问题。
-
作为链接答案的原始作者,并且做出了相同的决定(使用按值传递以避免双重锁定),我觉得我必须说明两种方法之间的关键区别,即碰巧评论太长了,所以我正在编辑答案。
标签: c++ c++11 mutex copy-and-swap