我很难找到有关 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::mt19937
或 std::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/