Блокировка нескольких мьютексов

Мне интересно, можно ли одновременно блокировать несколько мьютексов, например:

 Mutex1.Lock();
 {
     Mutex2.Lock();
     {
          // Code locked by mutex 1 and 2.
     }
     Mutex2.Unlock();

     // Code locked by mutex 1.
 }
 Mutex1.Unlock();

Это было бы очень полезно для некоторых ситуаций. Спасибо.

Ответ 1

Возможно, но порядок блокировки должен быть согласованным во всем приложении, в противном случае тупик является вероятным результатом (если два потока получают блокировки в противоположном порядке, то каждый поток может ждать на другом, чтобы освободить один из замков).

Порекомендуйте использовать блокировку с блокировкой и разблокировкой для обеспечения безопасности исключений, чтобы гарантировать, что блокировки всегда отпускаются (std::lock_guard с std::mutex, например):

std::mutex mtx1;
std::mutex mtx2;

std::lock_guard<std::mutex> mtx1_lock(mtx1);
{
    std::lock_guard<std::mutex> mtx2_lock(mtx2);
    {
    }
}

Если ваш компилятор не поддерживает эти возможности С++ 11, то boost имеет схожесть в boost::mutex и boost::lock_guard.

Ответ 2

std::lock, похоже, существует для этой цели.

Заблокирует данные Locklock objects lock1, lock2,..., lockn, используя алгоритм избежания тупиковой ситуации, чтобы избежать тупиковой ситуации. Объекты блокируются неуказанной серией вызовов блокировки, try_lock, разблокировки. Если вызов блокировки или разблокировки приводит к исключению, разблокировка вызывается для любых заблокированных объектов перед повторным запуском.

http://en.cppreference.com/w/cpp/thread/lock

Ответ 3

С++ 17 также предоставляет scoped_lock для конкретной цели блокировки нескольких мьютексов, которые предотвращают взаимоблокировку в стиле RAII, аналогично lock_guard.

#include<mutex>

std::mutex mtx1, mtx2;
void foo()
{
    std::scoped_lock lck{mtx1, mtx2};
    // proceed
}