私は C++ を学んでいますが、スコープ ロックのソース コードは非常に単純であることがわかりました。. どのように機能し、これは「Resource Acquisition is Instantiation」(RAII) の例ですか?
3 に答える
スコープ ロックを示す小さなコードを次に示します。
void do_something()
{
//here in the constructor of scoped_lock, the mutex is locked,
//and a reference to it is kept in the object `lock` for future use
scoped_lock lock(shared_mutex_obj);
//here goes the critical section code
}//<---here : the object `lock` goes out of scope
//that means, the destructor of scoped_lock will run.
//in the destructor, the mutex is unlocked.
コメントを読んでください。これは、scoped_lock がどのように機能するかを説明しています。
そして、これscoped_lock
が通常の実装方法です(最小限のコード):
class scoped_lock : noncopyable
{
mutex_impl &_mtx; //keep ref to the mutex passed to the constructor
public:
scoped_lock(mutex_impl & mtx ) : _mtx(mtx)
{
_mtx.lock(); //lock the mutex in the constructor
}
~scoped_lock()
{
_mtx.unlock(); //unlock the mutex in the constructor
}
};
RAII (Resource Acquisition Is Initialisation) の考え方は、オブジェクトの作成と初期化が 1 つの不可分なアクションに結合されるというものです。これは通常、オブジェクトのコンストラクターで実行されることを意味します。
スコープ付きロックは、ミューテックスが構築されたときにロックし、破棄されたときにロックを解除することによって機能します。C++ の規則は、制御フローが (例外を介してでも) スコープを離れるときに、終了するスコープにローカルなオブジェクトが正しく破棄されることを保証します。これは、手動で呼び出す代わりにスコープ付きロックを使用することを意味しlock()
、たとえばとunlock()
の間のコードの途中で例外がスローされた場合など、誤ってミューテックスをロック解除しないことを不可能にします。lock()
unlock()
この原則は、ミューテックスのロックだけでなく、解放する必要があるリソースを取得するすべてのシナリオに適用されます。このような「スコープ ガード」クラスを、同様の構文を持つ他の操作に提供することをお勧めします。
たとえば、私は最近、通常は変更時にシグナルを送信するデータ構造クラスに取り組みましたが、一部の一括操作ではこれらを無効にする必要があります。構築時にそれらを無効にし、破棄時に再び有効にするスコープ ガード クラスを提供することで、無効化/有効化関数への不均衡な呼び出しの可能性を防ぎます。
基本的には次のように機能します。
template <class Lockable>
class lock{
public:
lock(Lockable & m) : mtx(m){
mtx.lock();
}
~lock(){
mtx.unlock();
}
private:
Lockable & mtx;
};
のように使うと
int some_function_which_uses_mtx(){
lock<std::mutex> lock(mtx);
/* Work with a resource locked by mutex */
if( some_condition())
return 1;
if( some_other_condition())
return 1;
function_witch_might_throw();
return;
}
スコープベースの有効期間を持つ新しいオブジェクトを作成します。現在のスコープから離れ、このロックが破棄されるたびに、自動的に が呼び出されますmtx.unlock()
。この特定の例では、mutex のロックは RAIII のコンストラクターによって取得されることに注意してくださいlock
。
スコープガードなしでこれを行うにはどうすればよいですか? mtx.unlock()
関数を終了するたびに呼び出す必要があります。これは、a) 面倒で、b) エラーが発生しやすいです。また、スコープガードなしでは、リターン後にミューテックスを解放することはできません。