По словам этот, unique_lock
может быть использован для рекурсивной блокировки, объявив std::unique_lock<std::recursive_mutex>
и на самом деле это хорошо компилируется.
Однако из анализа кода (gcc 4.8.2 и 4.9.0) следует, что unique_lock
не откладывает _Mutex.lock
, а скорее реализует сам метод блокировки:
void
lock()
{
if (!_M_device)
__throw_system_error(int(errc::operation_not_permitted));
else if (_M_owns)
__throw_system_error(int(errc::resource_deadlock_would_occur));
else
{
_M_device->lock();
_M_owns = true;
}
Ясно, что это предотвращает рекурсивную блокировку мьютекса, и фактически попытка рекурсивной блокировки выдает resource_deadlock_would_occur
исключение.
Я что-то здесь упускаю, это ошибка, или документация для unique_lock просто неверна?
ТИА !!!
Распространенная ошибка — спутать mutex
с lock
, mutex
это объект, который может быть разделен между потоками (в противном случае он будет бесполезен). Однако блокировка сама по себе не является потокобезопасным объектом. Это не должно быть разделено между потоками. Обычно это локальный объект в стеке. Например:
void foo()
{
std::unique_lock<std::mutex> lk(mut); // mut comes from some other scope
// mut locked here
// ...
} // mut unlocked here
В приведенном выше примере, если foo()
вызывается рекурсивно, у вас неопределенное поведение, потому что вы заблокируете mut
рекурсивно. На каждой рекурсии вы получаете новый unique_lock
хоть. Итак unique_lock
не знает о рекурсии. Если вам действительно нужно позвонить foo()
рекурсивно, вам нужно использовать рекурсивный мьютекс, например:
void foo()
{
std::unique_lock<std::recursive_mutex> lk(mut); // mut comes from some other scope
// mut locked here
// ...
} // mut unlocked here
Итак: да, вы можете использовать std::unique_lock<std::recursive_mutex>
и да, ваша реализация верна.