【发布时间】:2017-06-11 04:13:52
【问题描述】:
我正在多个线程上运行蒙特卡罗模拟。我有一个处理随机数生成的 Draw 类。它使用mt19937-64作为std::uniform_real_distribution的生成器。
template<typename T, typename R>
class Draw {
T _dist;
typedef decltype(_dist.min()) result_type;
public:
// Draw : T R -> Draw
//! GIVEN
//! 1. dist - A distribution.
//! 2. gen - A random number generator.
Draw(T dist, R gen) : _dist(dist), _gen(gen) {}
virtual ~Draw() = default;
// () : -> Value
//! GIVEN
//! RETURNS
//! value drawn from the distribution, which can be any result type
//! supported by the distribution.
result_type operator()() const { return _draw(); }
// seed : NonNegInt -> Void
//! GIVEN
//! 1. seed - A random number generator (RNG) seed.
//! EFFECT
//! Seeds the RNG with the given seed.
void seed(unsigned long seed) { _gen.seed(seed);}
private:
R _gen;
// draw : -> Value
// GIVEN:
// RETURNS: A value drawn from the distribution, which can be any result
// type supported by the distribution.
std::function<result_type()> _draw = bind(_dist,_gen);
};
// standard uniform distribution ~ Unif(a=0, b=1)
class DrawUnif :
public Draw<std::uniform_real_distribution<double>,std::mt19937_64>
{
typedef std::mt19937_64 genny;
typedef std::chrono::system_clock clk;
typedef std::uniform_real_distribution<double> dist;
public:
DrawUnif() :
Draw(dist{0,1}, genny(clk::now().time_since_epoch().count())) {}
//! GIVEN
//! -----
//! 1. seed - A seed for the random number generator.
DrawUnif(unsigned long seed) : Draw(dist{0,1}, genny(seed)) {}
virtual ~DrawUnif() = default;
};
每个线程都可以访问下面的共享指针
typedef std::shared_ptr<DrawUnif> DrawUnifShrPtr;
DrawUnifShrPtr _unif;
由哪个初始化
_unif(DrawUnifShrPtr(new DrawUnif { seed }));
每个线程都有几个函数,它们经常调用draw(*_unif) 来生成一个随机数。结果似乎正确,但我想知道是否有两个线程调用
draw(*_unif)
同时,会发生什么?
然后我为每个队列分配了一个具有不同种子的新 shared_pointer:
_unif(std::make_shared<DrawUnif>(*c._unif));
_unif->seed(a_new_seed);
现在结果看起来很奇怪!每个线程都得到完全相同的随机!数字并提供完全相同的结果。 总结一下:
1- 如果多个胎面同时调用平局会发生什么?
2- 为什么不同的种子会得到完全相同的结果。
【问题讨论】:
-
我以前没有处理过这个问题,所以我不能 100% 确定这一点,但我认为 STL 随机库在同时被调用方面不是线程安全的. (您可以在多个线程中使用一个生成器/分发,只要您处理我相信的同步)。此外,在多线程环境中播种随机数生成器的另一个问题是,如果您基于时间播种,很多时间函数都有课程分辨率,因此多个线程在大约同一时间调用相同的东西很可能会得到结果相同。
标签: c++ multithreading random mersenne-twister