mersenne twister线程对cpp是否安全

时间:2016-11-17 13:10:22

标签: c++ multithreading c++11 mersenne-twister

#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());是否真实?

2 个答案:

答案 0 :(得分:5)

  

多个线程可以安全地调用此函数吗?功能线程安全吗?

此特定功能是线程安全的。可以创建随机数生成器,引擎和发行版,并在多个线程中调用函数本地引擎中的数字。

当然,由于cout未同步,因此多个线程的输出可以交错。

  

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

这就是你的功能所做的,虽然这确保了线程安全,但它与你需要做的相反。每次初始化引擎将使“随机性”序列直接取决于播种机。它当然会增加初始化引擎的开销。

  

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

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

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

答案 1 :(得分:5)

没有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是没用的。

传统上,您从engine创建mt19937(某种类型,如seeder一次。然后存储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