解锁lock_guard手动未定义/坏设计?

时间:2017-12-07 21:42:43

标签: c++ c++11 mutex

我有类似的代码:

do {
    lock_guard<mutex> lck(globalMtx);
    auto itr = someMap.end();
    for (/*conditions*/){
        //do stuff with itr and someMap
        // if a certain condition is met, we exit function with a return
        // globalMtx needs to be unlocked at that time
    }
    if (itr == someMap.end()){
        // I need to unlock the globalMtx here
        globalMtx.unlock()
        // A command is sent to modify someMap before we try again
        this_thread::sleep_for( chrono::seconds( 5 ) );
    } else {
        break;
    }
} while (true);

正如你在if范围中看到的,我需要解锁globalMtx,以便我可以修改&#34; someMap&#34;然后再次通过它。我已经阅读了许多线程/论坛/使用mutex.lock()/ unlock()手动锁定互斥锁是一个坏主意,通常不再使用c ++ 11或更高版本。

那么在这种情况下我可以根据需要控制互斥锁,同时仍然可以防止任何离开示波器的情况使互斥锁被锁定?

3 个答案:

答案 0 :(得分:8)

不,在这种情况下,您不应直接致电std::mutex::unlock(),因为std::lock_guard析构函数会再次调用std::mutex::unlock(),这将导致UB。您可以使用std::unique_lock代替std::lock_guard轻量级,但允许您在其上调用unlock()

std::unique_lock<mutex> lck(globalMtx);
...
lck.unlock(); // lck object is aware that globalMtx is released and would do nothing in it's dtor after this

答案 1 :(得分:2)

是的,这是一个坏主意,因为lock_guard在销毁互斥锁​​时仍会解锁互斥锁,因此互斥锁最终会被解锁两次。这会导致未定义的行为(即如果你很幸运就会崩溃)。

相反,请使用std::unique_lock。这有一个unlock()方法,它不仅可以调用底层互斥锁的unlock方法,还可以保证unique_lock对象不会再次解锁互斥锁。

答案 2 :(得分:1)

写一个像lock_guard一样的包装器,它跟踪互斥锁是否被保持,只有在被保持时才解锁。包装器应该同时具有解锁和重新锁定(如果已经锁定,则为无操作) ..