私はこのようなコードを持っています:
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のロックを解除して、「someMap」を変更してから再度実行できるようにする必要があります。私は多くのスレッド/フォーラム/mutex.lock()/ unlock()を使用してミューテックスを手動でロックすることは悪い考えであり、通常c ++ 11以降ではもう行われないことを読みました。
では、この場合、スコープを離れるとミューテックスがロックされたままになるのを防ぎながら、必要に応じてミューテックスを制御するにはどうすればよいでしょうか。
いいえ、この場合、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
_
はい、それは悪い考えです。_lock_guard
_は、破壊されたときにミューテックスのロックを解除するため、ミューテックスは2回ロック解除されることになります。これにより、未定義の動作が発生します(つまり、運が良ければクラッシュします)。
代わりに、_std::unique_lock
_を使用してください。これにはunlock()
メソッドがあり、基礎となるミューテックスのunlock
メソッドを呼び出すだけでなく、_unique_lock
_オブジェクトがミューテックスのロックを再度解除しないことも保証します。
ミューテックスが保持されているかどうかを追跡し、保持されている場合にのみ破棄時にロックを解除するlock_guardのようなラッパーを記述します。ラッパーには、ロック解除と再ロックの両方が必要です(ロックがすでに保持されている場合は何もしません)。