2016-09-23 10 views
3

サンプルコード。std :: unique_ptrのSTLコンテナからのfind()のスレッドセーフ

class Obj 
{ 
    public: 
    void doSome(void) 
    { 
     std::cout << "Hello World!" << std::endl; 
    } 
}; 

std::unordered_map<int, std::unique_ptr<Obj>> map; 

// insert -- done with single thread and before find() 
map[123] = std::move(std::unique_ptr<Obj>(new Obj)); 

// find -- run from multiple threads 
auto search = map.find(123); // <=== (Q) 
if (search != map.end())  
{ 
    search->second->doSome(); 
} 

(Q)

を実行している複数のスレッドがある場合は、// map.find(123)セクションを見つけるどのようにスレッドセイフティは?

map.find(123)は常にすべてのスレッドOBJを見つけるのだろうか? 検索 - > secondが他の誰かに割り当てられていない限り、

+1

注:関数から返されたもの(変数名なしのもの)は移動しないでください。それは役に立たない。 –

+2

非const関数も同時に呼び出されない限り、標準ライブラリクラス( 'find'など)の' const'メンバ関数を呼び出すことは大丈夫です。 –

答えて

0

find()のいずれも、順序付けられていないマップのどの方法もスレッドセーフではありません。 1つの実行スレッドがfind()を呼び出す可能性がある場合、他のスレッドがそれを変更する順序付けられていないマップメソッドを呼び出すと、結果として未定義の動作が発生します。

複数の実行スレッドが同じキーを使用してfind()を呼び出している場合、未定義の動作がない場合、すべての実行スレッドはそのキーに対して同じ値を取得します。

+1

正解です。読みづらいです。 –

1

複数のスレッドが同じ変数にアクセスし、の少なくとも1つがそれに書き込む場合、にはデータ競合があります。誰もが同じデータを読んでいるわけではありません。大丈夫。ただし、このコードでは対応していない別の問題があります。データがマップオブジェクトに格納されるタイミングによっては、マップオブジェクトの更新バージョンが表示されないスレッドがあります。この同期の問題を処理する最も簡単な方法は、リーダースレッドのいずれかを作成する前にマップオブジェクトを設定することです。

+0

答えの2番目の部分について:マップオブジェクトが既にセットアップされているときに、別のスレッドが既に読み取っているときにデータ競合ではないのですか? –

+0

@ChristianHackl - はい、データ競合には潜在的に同時に読み書きが行われます。私の答えの2番目の部分は、データ競争ではなく、変更の可視性についてです。たとえば、マップが1つのスレッドによって作成された場合、変更の結果は、そのスレッドが実行されたプロセッサキャッシュ内に存在し、別のプロセッサ上で実行されている他のスレッドは、更新。新しく作成されたスレッドは、それを作成したスレッドによって行われたすべてのグローバルな変更を常に表示します。なぜなら、マップが初期化されるまでスレッドを作成しない方が問題を解決するからです。 –

関連する問題