Вызов разблокировки мьютекса, когда он не заблокирован?

#c #locking #mutex

#c #блокировка #мьютекс

Вопрос:

У меня есть if-ветвь, например:

   MLOCK.lock();
  if (CPRIMES[snode->cid] == snode) {
    CPRIMES.erase(snode->cid);
    log("[remove_storage_node] Node "   kv_addr   " dropped as primary", VB);
    MLOCK.unlock();
    elect_new_primary(snode->cid);
  }
  MLOCK.unlock();
 

Я хочу убедиться, что блокировка разблокирована перед вызовом elect_new_primary , а также в конце блока кода. Это плохая практика? Какой лучший способ обеспечить разблокировку блокировки таким образом?

Комментарии:

1. Вы пробовали, что происходит? Я бы рекомендовал std::lock_guard вместо этого использовать s.

Ответ №1:

Предполагается, что этот ответ MLOCK относится к стандартному объекту мьютекса std::mutex .

От std::mutex::unlock :

Мьютекс должен быть заблокирован текущим потоком выполнения, в противном случае поведение не определено.

Следовательно, ваш код имеет неопределенное поведение при попытке разблокировать разблокированный мьютекс.

Такого рода проблемы лучше всего решать с помощью стандартного класса std::unique_lock . Этот класс будет управлять блокировкой и, когда его собственное время жизни закончится, он обязательно разблокирует мьютекс, если он все еще заблокирован.

Например :

 #include <mutex>

std::mutex m;

void foo(bool b)
{
    // Lock `m` and take ownership of that lock
    std::unique_lock<std::mutex> lock{m};

    if(b) { 
        // Unlocks `m`
        lock.unlock();
    }
}   // `m` will be unlocked if it wasn't unlocked previously
 

Вы должны очень редко прибегать к прямому вызову lock unlock функций-членов or mutex объекта.

Ответ №2:

Из cppreference:

std::mutex::unlock Разблокирует мьютекс. Мьютекс должен быть заблокирован текущим потоком выполнения, в противном случае поведение не определено.

Так что нет, вы не должны этого делать. Вместо этого вы должны отслеживать, заблокировали ли вы его, используя std::lock_guard или каким-либо другим способом.