假设我们有class
std::mutex
:
class Foo
{
std::mutex mutex_;
std::string str_;
// other members etc
public:
friend void swap(Foo& lhs, Foo& rhs) noexcept;
}
在这里实施swap
方法的适当方法是什么?是否需要/安全地分别锁定每个互斥锁然后交换所有内容? e.g。
void swap(Foo& lhs, Foo& rhs) noexcept
{
using std::swap;
std::lock_guard<std::mutex> lock_lhs {lhs.mutex_}, lock_rhs {rhs.mutex_};
swap(ls.str_, rhs.str_);
// swap everything else
}
我已经看到,在C ++ 17中,std::lock_guard
将constructor使用多个互斥锁来避免死锁,但我不确定这是否存在问题?
答案 0 :(得分:11)
您可以使用std::lock()
以非死锁的方式获取锁。
如果您想使用std::lock_guard
,请让他们采用锁定后的一次锁定:
std::lock(lhs.mutex_, rhs.mutex_);
std::lock_guard<std::mutex> lock_a(lhs.mutex_, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.mutex_, std::adopt_lock);
//swap actions
swap(ls.str_, rhs.str_);
如果您更喜欢std::unique_lock
,请在不锁定的情况下构建它们,然后调用std::lock()
将它们锁定(这也适用于std::lock_guard
):
std::unique_lock<std::mutex> lock_a(lhs.mutex_, std::defer_lock);
std::unique_lock<std::mutex> lock_b(rhs.mutex_, std::defer_lock);
std::lock(lock_a, lock_b);
//swap actions
swap(ls.str_, rhs.str_);
在这两种情况下,您应首先测试lhs
和rhs
是否为同一个对象,因为将std::lock
与一个互斥锁一起使用两次是未定义的行为:
if (&lhs == &rhs)
return;
答案 1 :(得分:2)
我认为您的交换实施是安全的。如果另一个算法尝试先锁定rhs.mutex_
然后再lhs.mutex_
,则可能会导致死锁。请改为std::lock()
。