2016-11-17 74 views
-2
#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());是还款吗?mersenne twister线程是否安全cpp

+2

为什么是“C”标签?这与C.无关。 – UnholySheep

+0

我不明白为什么我收到downvotes。我在问这是否线程安全,如果是更新种子的话。 – cateof

+0

可能是因为类似的问题有冗长而详细的答案? –

回答

1

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

Traditionaly您从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); 

这为每个线程创建一个engineengine与您random_device值进行初始化。

2

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

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

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

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

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

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

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

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

+0

我有更新的问题。 – cateof