1

関数に入る前に 1 つ以上のミューテックスをロックする必要がある関数が作成されることがあります。この要件が指定されていない場合、関数は、入力する前に関連するロックを取得せずに呼び出される可能性があり、壊滅的な結果をもたらす可能性があります。

現在、関数のドキュメントでこのようなことを指定することは可能ですが、私はそれが本当に好きではありません。

関数の前提条件(関数に入る際のアサート)に指定しようと思ったのですが、どのような条件にすればよいのでしょうか?

C++11 の std::mutex に has_lock() 関数があったとしても、私がロックを持っているという保証はありません。

4

2 に答える 2

3

再帰的ミューテックスを本当に使用したくなく、現在のスレッドがミューテックスを取得しようとせずに保持しているかどうかを確認することが目的の場合は、ミューテックス ラッパーを定義するのがおそらく簡単な解決策です。ここにワイルドショットがあります:

#include <thread>
#include <mutex>
#include <iostream>

using namespace std;

template<typename M>
struct mutex_wrapper
{
    void lock() 
    { 
        m.lock(); 
        lock_guard<mutex> l(idGuardMutex); 
        threadId = this_thread::get_id();
    }

    void unlock() 
    { 
        lock_guard<mutex> l(idGuardMutex); 
        threadId = thread::id(); 
        m.unlock(); 
    }

    bool is_held_by_current_thread() const 
    { 
        lock_guard<mutex> l(idGuardMutex); 
        return (threadId == this_thread::get_id()); 
    }

private:

    mutable mutex idGuardMutex;
    thread::id threadId;
    M m;
};

そして、これを使用する方法の簡単な例を次に示します。

int main()
{
    cout << boolalpha;
    mutex_wrapper<mutex> m;
    m.lock();
    cout << m.is_held_by_current_thread() << endl;
    m.unlock();
    cout << m.is_held_by_current_thread() << endl;
}
于 2013-01-25T15:10:12.243 に答える
2

あなたのジレンマに対する答えは、単に外部ミューテックスを使用しないことだと思います。同期が必要なリソースをクラスが管理する場合は、内部ミューテックスを使用してすべての同期を処理する必要があります。外部ミューテックスは、デッドロックと非同期アクセスの両方の可能性をもたらすため、危険です。

コメントから、あなたが苦労している問題は、同期されたコレクションのリファクタリングであるように思えます。一部のコードをクラスから移動したいが、そのコードを同期する必要がある。これを行う方法の例を次に示します。

class MyCollection {
private:
    std::list<Foo> items;
    std::mutex lock;

public:
    template <class F> void ForEach( F function )
    {
        std::lock_guard<decltype(this->lock) guard( this->lock );

        for( auto item : items )
            function( *item );
    }
};

この手法には、依然としてデッドロックの可能性があります。function パラメータは任意の関数であるため、コレクションにアクセスしてミューテックスを取得する可能性があります。一方、「ForEach」が読み取り専用である必要がある場合は、この動作が望ましい場合があります。

于 2013-01-25T15:44:13.673 に答える