9

私は C++ を学んでいますが、スコープ ロックのソース コードは非常に単純であることがわかりました。. どのように機能し、これは「Resource Acquisition is Instantiation」(RAII) の例ですか?

4

3 に答える 3

18

スコープ ロックを示す小さなコードを次に示します。

 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
      }
};
于 2013-01-11T10:53:10.100 に答える
13

RAII (Resource Acquisition Is Initialisation) の考え方は、オブジェクトの作成と初期化が 1 つの不可分なアクションに結合されるというものです。これは通常、オブジェクトのコンストラクターで実行されることを意味します。

スコープ付きロックは、ミューテックスが構築されたときにロックし、破棄されたときにロックを解除することによって機能します。C++ の規則は、制御フローが (例外を介してでも) スコープを離れるときに、終了するスコープにローカルなオブジェクトが正しく破棄されることを保証します。これは、手動で呼び出す代わりにスコープ付きロックを使用することを意味しlock()、たとえばとunlock()の間のコードの途中で例外がスローされた場合など、誤ってミューテックスをロック解除しないことを不可能にします。lock()unlock()

この原則は、ミューテックスのロックだけでなく、解放する必要があるリソースを取得するすべてのシナリオに適用されます。このような「スコープ ガード」クラスを、同様の構文を持つ他の操作に提供することをお勧めします。

たとえば、私は最近、通常は変更時にシグナルを送信するデータ構造クラスに取り組みましたが、一部の一括操作ではこれらを無効にする必要があります。構築時にそれらを無効にし、破棄時に再び有効にするスコープ ガード クラスを提供することで、無効化/有効化関数への不均衡な呼び出しの可能性を防ぎます。

于 2013-01-11T10:57:06.157 に答える
4

基本的には次のように機能します。

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) エラーが発生しやすいです。また、スコープガードなしでは、リターンにミューテックスを解放することはできません。

于 2013-01-11T10:57:24.070 に答える