2016-11-17 2 views
-2
#include <random> 

int f() { 

    std::random_device seeder; 
    std::mt19937 engine(seeder()); 
    std::uniform_int_distribution<int> dist(1, 6); 

    return dist(engine); 

} 

複数のスレッドでこの関数を安全に呼び出すことはできますか?関数スレッドは安全ですか? 毎回std::random_device seeder;std::mt19937 engine(seeder());に電話するのは礼儀正しいですか?cppのmersenne twisterスレッドセーフです

+2

なぜ「C」タグですか?これはCとは関係ありません。 – UnholySheep

+0

なぜ私はdownvotesを受信して​​いるのか分かりません。私はこれがスレッドセーフであるかどうか、また種を更新するために再実行するかどうかを尋ねています。 – cateof

+0

おそらく、長くて詳細な回答がある同様の質問のためでしょうか? –

答えて

1

いいえC++ stdタイプはスレッドセーフではない方法でグローバルデータを使用します。このようなタイプの無関係な2つのインスタンスは、異なるスレッドでアクセスできます。

デフォルトでは、1つのタイプのインスタンスに、同期なしで2つのスレッドからアクセスすることはできません。

作成されたローカル変数。これらのローカル変数は、そのタイプの他のインスタンスとは無関係です。ここにはスレッドセーフの問題はありません。

疑似ランダム値は、状態を持ち再利用することで最も効率的に生成されます。あなたはこれをやっていないので、1から6までのあなたの乱数は、比較的高価なものになります。

std::random_device seeder; 
std::mt19937 engine(seeder()); 
std::uniform_int_distribution<int> dist(1, 6); 
return dist(engine); 

std::mt19937の使用は冗長です。 random_deviceを既に作成しています。distに直接送信してからengineを作成し、次にengineを使用して作成しました。ここでengineの使用は役に立たない。あなたは(mt19937のように、いくつかのタイプの)engineを作成

Traditionaly seederから一回。その後、engineを保管し、それを配布に繰り返し渡します。

これは、エンジンスルーディストリビューションによって長い一連の擬似乱数を生成するために、比較的高価な「実数乱数」生成を一度行います。

ただし、このような使用にはコストがかかります。 engineを格納する必要があります。また、複数スレッドへのアクセスを防止する必要があります。

これを行う「正しい」方法は、ランダムな値を生成するオブジェクトを用意し、必要な場所に渡すことです。使用された最初のシードを格納すると、関連する乱数のセットの実行を繰り返すこともできます。

あなたが明示的にランダムな状態の周りに渡すのアイデアを気に入らない場合は、(mutexガード付きまたはstaticthread_localを使用することができます。

thread_local std::mt19937 engine(std::random_device{}()); 
std::uniform_int_distribution<int> dist(1, 6); 
return dist(engine); 

これは、スレッドごとに1 engineを作成し、engineはあなたのrandom_deviceからの値で初期化されます。

2

複数のスレッドでこの関数を安全に呼び出すことはできますか?関数スレッドは安全ですか?

この特定の機能はスレッドセーフです。乱数ジェネレータ、エンジン、ディストリビューションを作成して、関数ローカルエンジンの数値を複数のスレッドで生成することは可能です。

もちろん、coutは同期されていないため、複数のスレッドからの出力をインターリーブすることができます。

私はそれが保証スレッドの安全性をしていますが、すべての関数呼び出し

でエンジンを初期化する必要がありますか、それはあなたが何をする必要があるかの反対です。毎回エンジンを初期化すると、「ランダム性」シーケンスはシーダーに直接依存します。もちろん、エンジンを初期化するためのオーバーヘッドが追加されます。

または最初の2行(シーダーとエンジン)をクラスコンストラクターに配置する方がよいでしょうか?

ラッパークラスを使用することはできますが、そうする必要はありません。これは、すべての関数呼び出しで新しいエンジンインスタンスを作成するかどうかとは正反対です。各関数呼び出しが以前の呼び出しと同じエンジンを使用している限り、その点でランダム性に問題はありません。

しかし、スレッド間で同じエンジンを使用することは、実際にはスレッドセーフではありません。代わりに、各スレッドで1つのエンジンを使用することも、共有エンジンをミューテックスで保護することもできますが、それには大きなオーバーヘッドがあります。

+0

私は質問を更新しました。 – cateof

関連する問題