Подтвердить что ты не робот

Реализация swap для класса с помощью std:: mutex

Предположим, что a class с a std::mutex:

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
}

Я видел, что в С++ 17, std::lock_guard будет иметь конструктор , используя несколько мьютексов, чтобы избежать взаимоблокировки, но я не уверен, проблема здесь?

4b9b3361

Ответ 1

Вы можете использовать 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 с одним мьютеком дважды - это поведение undefined:

if (&lhs == &rhs)
    return;

Ответ 2

Я не думаю, что ваша своп-реализация безопасна. Если другой алгоритм пытается сначала заблокировать rhs.mutex_, а затем lhs.mutex_, вы можете оказаться в тупике. Вместо этого попробуйте std::lock().