6

簡単な質問 - 基本的に、ミューテックスのロックを解除する必要がありますか、それともスコープ演算子を使用するだけでミューテックスが自動的にロック解除されますか?

すなわち:

{ 
    pthread_mutex_lock (&myMutex); 
    sharedResource++; 
} // my mutex is now unlocked?

または私はすべきですか:

{ 
    pthread_mutex_lock (&myMutex); 
    sharedResource++;
    pthread_mutex_unlock (&myMutex);
}
4

3 に答える 3

18

あなたの例では、ミューテックスは範囲外ではありません。また、スコープの最後で特定の関数を呼び出す必要があることをコンパイラが知る方法がないため、最初の例ではミューテックスのロックを解除しません。

(エラーが発生しやすい)関数を使用してミューテックスをロックおよびロック解除しているunlock()場合は、保護された操作が例外をスローした場合でも、常に呼び出すようにする必要があります。

これを行う最善の方法は、使用後に解放する必要がある他のリソースの場合と同様に、 RAIIクラスを使用してロックを管理することです。

class lock_guard {
public:
    explicit lock_guard(mutex & m) : m(m) {mutex_lock(m);}
    ~lock_guard() {mutex_unlock(m);}

    lock_guard(lock_guard const &) = delete;
    void operator=(lock_guard &) = delete;

private:
    mutex & m;
};

// Usage
{
    lock_guard lock(myMutex);
    shared_resource++;
} // mutex is unlocked here (even if an exception was thrown)

最新の C++ では、これにはstd::lock_guardorstd::unique_lockを使用します。

于 2013-07-18T16:52:46.287 に答える
2

この場合、このコードが範囲外になるとミューテックスはロック解除されません。

RAII に従うミューテックス ロッカーは、ヒープに割り当てられていないオブジェクトがスコープ外になると、デストラクタが自動的に呼び出されるという事実を利用します。次に、ミューテックスをロックしたオブジェクトが範囲外になると、ミューテックスのロックを解除します。コードの場合、中かっこのスコープ内にオブジェクトが割り当てられていないため、スコープが終了するとミューテックスがロック解除される可能性はありません。

たとえばQMutexLocker、Qt ライブラリから使用すると、スコープが終了したときにミューテックスのロックが解除されていることを確認できます。

{
    QMutexLocker locker(myMutex);
    if(checkSomething())
    {
        return;
    }
    doSomething();
}

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

{
    mutex_lock(myMutex);
    if(checkSomething())
    {
        mutex_unlock(myMutex);
        return;
    }
    doSomething();
    mutex_unlock(myMutex);
}

Brian Neal が指摘しているように、例外checkSomething()doSomething()スローするケースを安全に処理することはできません。

Qt の代替QMutexLockerは、STD のstd::lock_guardです。

于 2013-07-18T16:51:42.630 に答える
2

RAII スコープ メソッドを使用すると、例外や早期復帰が発生した場合でもミューテックスが常にロック解除されることが保証されるため、はるかに優れています。

C++11 にアクセスできる場合は、std::atomic<int>代わりに a を使用することを検討できます。この場合、インクリメントするためにロックする必要はありません。

于 2013-07-18T16:46:25.920 に答える