c++ - 在 C++ 中使用 rand() 或 std::random_device 生成安全随机数

标签 c++ multithreading random random-seed

我很难找到有关 C++ 中随机数生成的线程安全性的令人信服的资料来源。

我正在开发的应用程序目前只有很少的线程访问随机数生成,但将来可能会有更多。

首先使用的是:

int randomInRange(const int min, const int max)
{
    srand(time(0));
    return min + (rand() % max);
}

据我所知,这是错误的,因为种子是为每次调用设置的,它会对 rand() 函数的统计随机性和性能产生负面影响。

接下来尝试的是使用一个单例来保存 std::mt19937 的单个实例:

// RandomHelper.h
class RandomHelper
{
private:
    std::mt19937 engine;

    // Singleton
    RandomHelper() : engine(std::random_device()()) {}

public:
    static RandomHelper& getInstance();

    int randomInRange(int min, int max)
    {
        std::uniform_int_distribution<int> uidist(min, max);
        return uidist(engine);
    }
};

// RandomHelper.cpp
RandomHelper& RandomHelper::getInstance()
{
    static RandomHelper instance;
    return instance;
}

这应该有助于统计随机性。但为此,我知道每个线程有一个 std::mt19937 实例会更好。

我不确定我明白为什么。

这是因为如果多个线程同时调用 RandomHelper::getInstance().randomInRange(.., ..) 它们会得到相同的结果吗?又名它不是线程安全的?

为了避免这种可能性,现在实现如下:

int randomInRange(const int min, const int max)
{
    thread_local std::mt19937 engine(std::random_device{}());
    std::uniform_int_distribution<int> uidist(min, max);
    return uidist(engine);
}

这看起来是迄今为止最好的解决方案,但我找不到太多有关 std::mt19937std::random_device 线程安全的信息看看是否真的需要有一个 thread_local 变体,而不是单例中的单个实例。

我愿意做更多的研究,但除了通常的 C++ 引用文献之外,我不知道该去哪里寻找,据我所知,这些引用文献没有提到任何有关线程安全的内容。

最佳答案

随机数生成器引擎不是线程安全的。

使用thread_local为每个线程初始化一个引擎使其线程安全,所以我想说你的解决方案很好。

如果您对 random_device 的线程安全性有疑问,也许也可以将其设置为 thread_local:

int randomInRange(const int min, const int max)
{
    thread_local std::random_device rd;
    thread_local std::mt19937 rng(rd());  
    thread_local std::uniform_int_distribution<int> uid;
    return uid(rng, decltype(uid)::param_type{min,max});
}

还有更多主题讨论了未提及的问题:

C++ thread-safe uniform distribution random number generation

C++11 Thread safety of Random number generators

我确信还有更多。

关于c++ - 在 C++ 中使用 rand() 或 std::random_device 生成安全随机数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60450514/

相关文章:

c++ - 无法将元素插入嵌套的 STL 整数集中

c++ - 在 C/C++ 中编写 YUV 图像帧的问题

带有 OpenMP 线程安全随机数的 C++

java - 我们如何在 hibernate 中处理并发事务

Java:多线程和二维线程

ios - Swift 4 - 测验应用程序随机问题

c++ - C++中的排名树

c++ - 进程内运行线程的名称

c++ - 在 C/C++ 中获取大的随机数

python - 如何在Python中随机指定变量