В моей кодовой базе есть две функции, которые выглядят примерно так:
void inside() {
lock_guard<mutex> lock(LOCK);
cout << "Finished inside" << endl;
}
void outside() {
lock_guard<mutex> lock(LOCK);
inside();
cout << "Finished outside" << endl;
}
Это вызывает взаимоблокировку в моей кодовой базе, что я нахожу странным, потому что у меня сложилось впечатление, что lock_guard уничтожается, когда выходит за пределы области видимости. Я также пробовал с unique_lock, но получил тот же результат. Единственный способ, которым я смог решить эту проблему, - вызвать разблокировку перед вызовом внутрь:
void outside() {
LOCK.lock();
// Do stuff
LOCK.unlock();
inside();
cout << "Finished outside" << endl;
}
На мой взгляд, это выходит за рамки, если я не ошибаюсь
Он не выходит за рамки до тех пор, пока функция, в которой он определен, не завершится. В полезном упрощении область определяется ближайшими фигурными скобками {}, в которых определена переменная - в данном случае {} функции. Пока выполнение кода не завершит эту область, она находится в области.
Это объясняет, спасибо
У меня сложилось впечатление, что lock_guard уничтожается, когда выходит за рамки.
Оно делает. Проблема в том, что вы создаете 2 отдельных объекта lock_guard
в 2 разных областях. В outside()
вы создаете один объект, который остается в области видимости, пока inside()
работает. inside()
затем создает свой собственный объект, который выходит за рамки, когда inside()
выходит. Объект в outside()
остается в области до тех пор, пока outside()
не выйдет.
При этом обратите внимание, что std::mutex
не является повторным входом. Попытка заблокировать mutex
, когда блокировка уже принадлежит вызывающему потоку, является поведением undefined. У вас есть 2 lock_guard
объекта, пытающихся заблокировать один и тот же mutex
из одного потока. Вот почему вы зашли в тупик. Вам нужно будет использовать std::recursive_mutex
вместо этого, чтобы избежать этого. Поток может владеть несколькими блокировками для recursive_mutex
, если он правильно разблокирует их все.
В противном случае, если вы действительно хотите, чтобы outside()
разблокировал mutex
перед входом в inside()
, более чистый (и безопасный) способ справиться с этим — ввести новую область видимости в outside()
, например:
void outside() {
{ // <--- starts a new scope here
lock_guard<mutex> lock(LOCK);
// Do stuff
} // <-- ends the scope, destroying the lock_guard here
inside();
cout << "Finished outside" << endl;
}
Итак, мораль этой истории заключается в использовании recursive_mutex, если мьютекс используется несколькими потоками?
@doctopus • Нет, recursive_mutex, если мьютекс будет заблокирован в разных областях/цепочках вызовов в одном потоке.
Я понимаю. Спасибо
Ну что, вышло за рамки?