2017-09-25 5 views
1

私はshared_ptrでラップされたリソース "resource"を持っていて、他のスレッドからアクセスしたいと思っています。 私がこれをするとき:C++ return function lock_guard

// foo.h 
class Foo{ 
public: 
    std::shared_ptr<Setup> GetSomeThing(); 
    void SetSomeThing(); 
private: 
    std::shared_ptr<Setup> resource; 
    std::mutex lock; 
} 
//Foo.cpp 
std::shared_ptr<Setup> Foo::GetSomeThing() 
{ 
    std::lock_guard<std::mutex> lock (mutex); 
    return resource; 
} 

void Foo::SetSomeThing() 
{ 
    std::lock_guard<std::mutex> lock (mutex); 
    resource = ...; 
} 

それは大丈夫ですか? いつ返品オブジェクトが作成され、いつロックが破棄されるのですか?それはドキュメントの中に何か存在するのでしょうか? ありがとうございました!

+4

「ロック」はスコープ出口で破棄されるため、完全に無意味です。その代わりにthreadを呼び出すと、このロックが作成され、 'Foo :: GetSomeThing'が呼び出され、' lock'がまだ生きている間に同じ(または内部の)スコープで何かが処理されます。 – VTT

+1

すべてのスレッド間で共通のミューテックスを使用する必要があります。また、すべてのスレッドでlock_guardなどを使用する必要があります。例えばFooはstd :: mutex _mtxResourceを持っていなければなりません。次にstd :: lock_guard lock(foo._mtxResource);どこのスレッドでもリソースを使用する必要があります。 –

+0

@VTTコード例をもう一度見てください)それはまだ無意味ですか? – voltento

答えて

1

この答えは2行こと(明確にするために)を前提としています複数のスレッドが同期せずstd::shared_ptr<>の単一のインスタンスにアクセスした場合

std::lock_guard<std::mutex> lock (mutex); 

両方

std::lock_guard<std::mutex> guard (lock); 

で置き換えられたものコールのいずれか非constメンバーの場合、データ競合が発生します。

つまり、SetSomeThing()GetSomething()の間の同期を保証する必要があります。

std::mutexを紹介し、提案された方法でstd::lock_guard<>を使用してください。返されたコピーは、デストラクタguardが呼び出される前に構築されています。

これはほぼ同じインスタンスであることに注意してください。 GetSomeThing()によって返されたコピーには、他のインスタンスを同期させずにアクセスできる(非constであり、破壊さえさえする)ための十分な内部同期があります。

しかし、std::shared_ptr<Setup>が所有する共有オブジェクトSetup(part-)のデータ競合を防止するものはありません。 Setupへのすべてのアクセスが読み取り専用であれば、複数のスレッドがそれにアクセスできますが、スレッドが共有データに書き込むとデータ競合が発生します。

単純なアプリケーションでSetupのようなオブジェクトを構築し、初期化してから、複数のスレッドを起動してからメインスレッド以外のすべてが終了したときに破壊することができます。その特定の場合、それ以上の同期は必要なく、提供されたロックさえも余計です。ここで

は非規範的なリファレンスです:

http://en.cppreference.com/w/cpp/memory/shared_ptr

は、開口部の説明の最後の段落を参照してください。

脚注:アプリケーションの設定を変更することは、単に属性上にデータ競合が発生しないようにすることよりはるかに困難です。スレッドは、変更または「放棄」アクティビティの適用を保留する必要があるかもしれません。例えば、「描画」ステップ中に画面解像度が変更されるグラフィックプログラムを考える。ドローを終了し、大きすぎる/小さめのキャンバスを作成するか、部分描画キャンバスをダンプして新しい解像度を採用する必要がありますか?ドローイングは、「前」または「後」と一致し、無意味ではない(クラッシュする可能性のある)ハイブリッドではないものが得られるような方法で取得されていますか?