bugfix> c++ > 投稿

クラスインスタンスのすべての使用法をミューテックスでラップしたいと思います。今日は

std::map<int, std::shared_ptr<MyClass>> classes;

インスタンスを検索して返すための関数:

std::shared_ptr<MyClass> GetClass(int i);

GetClass()は、RAIIメカニズムを使用して、他の誰かがまだ取得していない場合にのみインスタンスを取得できるようにします。使用法は次のようになります。

void CallingFunction()
{
    auto c = GetClass(i); // mutex for class id 'i' is acquired here
    // some calls to class
    c.SomeFunction();
} // mutex is released here when 'c' goes out of scope

CallingFunction()によって取得されたミューテックスでは、同じクラスインスタンスにアクセスしたい他のスレッドは、GetClass()の呼び出しをブロックします。

次のようなラッパークラスを使用するなど、いくつかの方法を検討しています。

class ClassContainer
{
    public:
        std::shared_ptr<Class> c;
        std::mutex m;
};

GetClass()を次のように変更する場合:

ClassContainer GetClass(int i);

しかし、std :: mutexを保持する場所の両方を把握するのに問題があります。最初にマップに保存してから、次のようなコンテナクラスの使用に移行しました。

std::map<int, std::pair<std::mutex, std::shared_ptr<MyClass<>>> classes;

しかし、それはうまく機能していませんでしたが、ClassContainerではstd :: lock_guard<>のようにClassContainerがstd :: mutexをロックする方法があります呼び出し元がGetClass()の呼び出しを介して取得した場合。

回答 3 件
  • I've been looking at a few ways of doing it, such as with a wrapper class like:

    はい、これはそれを行う適切な方法であり、あなたは近くにいますが、あなたは mutex を保つことができません  このクラスでは、ロッカーのみです。そして、 std::unique_lock  必要なmove ctorなどがあるため、そのための適切なタイプです。ただし、フィールドをプライベートにし、必要なアクセサーを作成します。

    class ClassContainer
    {
        std::shared_ptr<Class> c;
        std::uniqe_lock<mutex> lock;
    public:
        ClassContainer( std::pair<std::mutex,std::shared_ptr<Class>> &p ) :
            c( p.second ),
            lock( p.first ) 
        {
        }
        Class * operator->()const { return c.get(); }
        Class & operator*() const { return *c; }
    };
    
    

    使い方は簡単です:

    void CallingFunction()
    {
        auto c = GetClass(i); // mutex for class id 'i' is acquired here
        // some calls to class
        c->SomeFunction();
        // or even
        GetClass(i)->SomeFunction();
    }
    
    

  • Class です   mutex を保持する必要があります 、 何かのようなもの:

    class Class
    {
    public:
        // Your methods...
        std::mutex& GetMutex() { return m; }
    private:
        std::mutex m;
    };
    class ClassContainer
    {
    public:
        ClassContainer(std::shared_ptr<Class> c) :
             c(std::move(c)),
             l(this->c->GetMutex())
        {}
        ClassContainer(const ClassContainer&) = delete;
        ClassContainer(ClassContainer&&) = delete;
        ClassContainer& operator =(const ClassContainer&) = default;
        ClassContainer& operator =(ClassContainer&&) = default;
        // For transparent pointer like access to Class.
        decltype(auto) operator -> () const { return c; }
        decltype(auto) operator -> () { return c; }
        const Class& operator*() const { return *c; }
        Class& operator*() { return *c; }
    private:
        std::shared_ptr<Class> c;
        std::lock_guard<std::mutex> l;
    };
    ClassContainer GetClass(int i)
    {
        auto c = std::make_shared<Class>();
        return {c}; // syntax which avoids copy/move contructor.
    }
    
    

    そして最後に使用法:

    auto&& cc = GetClass(42); // `auto&&` or `const&` pre-C++17, simple auto possible in C++17
    cc->ClassMethod();
    
    

    簡易デモ。

  • 偶然、私は最近非常に似たようなことをしました( shared_ptr の代わりにオブジェクトへの参照を返しました 。コードは次のように機能しました:

    struct locked_queue {
        locked_queue(locked_queue&& ) = default;
        mutable std::unique_lock<decltype(queue::mutex)> lock;
        const queue::q_impl_t& queue; // std::deque
    };
    
    

    そして、これがどのように使用されるかです:

    locked_queue ClassX::get_queue(...) {
        return {std::unique_lock<decltype(mutex)>{mutex}, queue_impl};
    }
    
    

あなたの答え