Может ли использование блокировки мьютекса, принятого lock_guard, привести к UB?
Может ли следующий фрагмент вызвать неповрежденное поведение из-за использования блокировки мьютекса, уже принятого lock_guard
? и будет ли безопасно, если я используюunique_lock
вместо того lock_guard
в том же фрагменте? Я знаю что естьstd::unique_lock<T>::lock/unlock()
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex m1;
void func(int count ){
std::lock_guard lG{m1};
std::cout << std::this_thread::get_id() << std::endl;
if(count == 1) {
m1.unlock();
std::this_thread::sleep_for(std::chrono::duration<size_t, std::ratio<1, 1>>{6});
m1.lock();
}
std::cout << std::this_thread::get_id() << std::endl;
}
int main()
{
std::thread t1 {func, 1};
std::thread t2 {func, 9};
t1.join();
t2.join();
}
1 ответ
Этот конкретный код, вероятно, безопасен, но я бы не считал его хорошим стилем. Проблема в том, что если что-то вызывает исключение междуm1.unlock()
а также m1.lock()
, то lock_guard
destructor собирается разблокировать разблокированный мьютекс во второй раз, вызывая UB. Таким образом, даже если все, что находится между этими операторами, гарантированно не бросит, читатель кода должен слишком внимательно изучить этот код, чтобы убедиться, что UB отсутствует.
Было бы намного лучше использовать unique_lock
и сделайте танец разблокировки / блокировки наunique_lock
вместо того, чтобы прямо на mutex
для обеспечения правильной разблокировки в исключительном случае.