を読んでいて、明示的なロックの使用例において、以下のようなtry-finally文を使っていました。
Lock scoreLock = new ReentrantLock(); ... void doSomething() { try { scoreLock.lock(); // 同期が必要な処理 } finally { scoreLock.unlock(); } }
try文の中で、実行時例外が投擲されたりreturn文を書いた場合でも、finally文が必ず実行されます。これを以下のように記述すると、NGです。
void doSomething() { scoreLock.lock(); // 同期が必要な処理 scoreLock.unlock(); }
処理の中で例外が発生すると、ロックが解放されず、デッドロックを引き起こします。
C++言語では、RAII(Resource Aquision Is Initialization)と呼ばれるイディオムがこの役割に相当します。
template <typename T> class locker { public: locker(T* p) : pLock(p) { pLock->lock(); } ~locker() { pLock->unlock(); } private: T* pLock; }; void doSomething() { locker theLocker(someLock); // 同期が必要な処理 }
まあ、C++の場合は例外等の中断が発生しない場合でも、メソッドから抜けるまでロックを獲得し続けるのでRAIIをロックに使用するのはあまりよい方法ではないかもしれません。