使用std :: mutex实现类的交换

时间:2016-01-18 11:17:02

标签: c++ multithreading c++11 mutex swap

假设我们有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_guardconstructor使用多个互斥锁来避免死锁,但我不确定这是否存在问题?

2 个答案:

答案 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_);

在这两种情况下,您应首先测试lhsrhs是否为同一个对象,因为将std::lock与一个互斥锁一起使用两次是未定义的行为:

if (&lhs == &rhs)
    return;

答案 1 :(得分:2)

我认为您的交换实施是安全的。如果另一个算法尝试先锁定rhs.mutex_然后再lhs.mutex_,则可能会导致死锁。请改为std::lock()