#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());
是否真实?
答案 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
(或static
和mutex
后卫。
thread_local std::mt19937 engine(std::random_device{}());
std::uniform_int_distribution<int> dist(1, 6);
return dist(engine);
这会为每个帖子创建一个engine
,并使用engine
中的值初始化random_device
。