web-dev-qa-db-ja.com

C ++でロックをキャッチしてみてください

Javaの場合:

Lock lock = new ReentrantLock();
try{
  lock.lock();
  someFunctionLikelyToCauseAnException();
}
catch(e){...}
finally {
  lock.unlock();
}

私の質問は、上記の例では、最終的に常に実行されるため、ロックが常にロック解除されることを知っていますが、C++の保証は何ですか?

mutex m;
m.lock();
someFunctionLikelyToCauseAnException();
/// ????

これはどのように機能し、なぜですか?

38

このために、 RAII-style コンストラクト std::lock_guard を使用します。使用するとき

std::mutex m;
{ // start of some scope
    std::lock_guard lg(m);
    // stuff
} // end of scope

lgは、スコープの出口でスコープがどのパスに残されても、mがロック解除され、std::lock_guardsデストラクタがunlockを呼び出すようにします。

例外がスローされた場合でも、スタックは巻き戻され( スタックの巻き戻し )、そのプロセスはlgを破棄し、次にunlockを呼び出してロックの解放を保証します。

61
NathanOliver

c ++の保証は何ですか?

C++の関連する保証は、Javaで言及した保証とは少し異なります。 最終ブロックの代わりに、自動変数の破壊に依存していますスタックフレームが解かれると、スコープの終了時に発生します。この stack unwinding は、gracefullyまたは例外が原因です。

このようなlocksに関するシナリオの好ましいアプローチは、 RAII を使用することです。たとえば std::lock_guard 。コンストラクターに渡されるmutexオブジェクトを保持し、その内部でmutexlock()メソッドを呼び出し、その後でスレッドがミューテックスを所有します-そしてstack unwindingスコープの出口でデストラクタが呼び出されます-その内部でmutexunlock()メソッドを呼び出し、それを解放します。

コードは次のようになります。

std::mutex m;
{
    std::lock_guard lock(m);
    // Everything here is mutex-protected.
}
// Here you are guaranteed the std::mutex is released.
29

クリティカルセクションによって保護されているコード、つまり「lock()」と「unlock()」の間のコードの実行中に例外がスローされた場合、コードが動作している関連オブジェクトはもはや存在しないことを意味します有効な状態。これは、例外によってトリガーされるスタックの自動巻き戻しによってロールバックされる場合とされない場合があります、例外がスローされる前に何らかの副作用が発生した可能性があるためソケットを介して送信された場合、たとえば、マシンが起動されました。この時点での大きな問題は、mutexがリリースされるかどうかではありません(代わりにlock_guardを使用することによる唯一の保証)。まだロックされているミューテックスが望ましい動作であり、呼び出し元がすべての混乱をクリーンアップした後に明示的にリセットできる場合があります。

私のポイントは、これは言語の問題ではないということです。言語機能は、正しいエラー処理を保証できません。 lock_guardとRAIIを特効薬として受け取らないでください。

0
John Z. Li