mersenne twister 线程对 cpp 是不是安全

Posted

技术标签:

【中文标题】mersenne twister 线程对 cpp 是不是安全【英文标题】:Is mersenne twister thread safe for cppmersenne twister 线程对 cpp 是否安全 【发布时间】:2017-04-01 01:10:59 【问题描述】:
#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()); 是多余的吗?

【问题讨论】:

为什么是“C”标签?这与 C 无关。 我真的不明白为什么我会收到反对票。我在问这是否是线程安全的,以及更新种子是否是多余的。 可能是因为类似问题的答案冗长而详细? 您的代码不足以说明线程安全的含义。初始化?一代?多个实例? How do I generate thread-safe uniform random numbers?的可能重复 【参考方案1】:

No C++ std 类型以非线程安全的方式使用全局数据。这种类型的两个不相关的实例可以在不同的线程中访问。

默认情况下,一个类型的一个实例不能在没有同步的情况下被两个线程访问。

您被创建了局部变量。这些局部变量与其类型的任何其他实例无关。这里没有线程安全问题。

通过拥有状态并重用它来最有效地生成伪随机值。您没有这样做,因此创建 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是没用的。

传统上,您从seeder 创建一个engine(某种类型,例如mt19937一次。然后存储engine,并反复将其传递给发行版。

这会执行一次相对昂贵的“真实随机数”生成,以通过引擎通过分发生成一长串伪随机数。

但是请注意,这种使用是有代价的;您必须存储 engine 并且必须防止多线程访问它。

执行此操作的“正确”方法是拥有一个为您生成随机值的对象,并将其传递到您需要的地方。存储使用的初始种子还允许您重复执行所涉及的一组随机数。

如果您不喜欢明确传递随机状态的想法,您可以使用thread_local(或staticmutex 保护)。

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

这会为每个线程创建一个engine,并且engine 会使用您的random_device 中的值进行初始化。

【讨论】:

【参考方案2】:

多个线程可以安全地调用这个函数吗?函数线程安全吗?

这个特殊的函数是线程安全的。可以创建随机数生成器、引擎和分布,在函数本地引擎中多线程调用生成数。

当然,来自多个线程的输出可以交错,因为cout 不同步。

是否需要在每个函数调用中初始化引擎

这就是你的函数所做的,虽然这确实保证了线程安全,但它与你需要做的相反。每次初始化引擎都会使“随机”序列直接依赖于播种机。而且它当然会增加初始化引擎的开销。

或者将前两行(种子和引擎)放在类构造函数中会更好吗?

您可以使用包装类,但不是必须的。这与您是否在每个函数调用中创建一个新的引擎实例是正交的。只要每个函数调用使用与之前调用相同的引擎,这方面的随机性就没有问题。

但是跨线程使用相同的引擎确实不是线程安全的。您可以改为在每个线程中使用一个引擎 - 或使用互斥锁保护共享引擎,但这会产生大量开销。

【讨论】:

以上是关于mersenne twister 线程对 cpp 是不是安全的主要内容,如果未能解决你的问题,请参考以下文章

Mersenne Twister 与 Mersenne Twister 64 位

实现 64 位 Mersenne Twister - 定义

C# Mersenne Twister 随机整数生成器实现 (SFMT) 蒙特卡罗模拟

伪随机数生成算法-梅森旋转(Mersenne Twister/MT)

为啥在梯度噪声发生器中从 Mersenne twister 切换到其他 PRNG 会产生不好的结果?

将随机整数转换为范围 [min,max] 而不进行分支