使用 std::mutex 实现类交换

Implementing swap for class with std::mutex

本文关键字:交换 实现 mutex std 使用      更新时间:2023-10-16

>假设我们有一个带有std::mutexclass

class Foo
{
    std::mutex mutex_;
    std::string str_;
    // other members etc
public:
    friend void swap(Foo& lhs, Foo& rhs) noexcept;
}

在这里实现swap方法的适当方法是什么?是否需要/安全地单独锁定每个互斥锁,然后交换所有内容?例如

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会有一个构造函数采用多个互斥体来避免死锁,但我不确定这是否是这里的问题?

您可以使用

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;

我认为您的交换实现不安全。如果另一种算法尝试先锁定rhs.mutex_然后lhs.mutex_,则最终可能会陷入死锁。请尝试std::lock()