从多个线程使用stdlib的rand()

时间:2011-05-28 11:22:14

标签: c++ c multithreading random

我有几个线程都运行相同的功能。在每个中,它们会多次生成不同的随机数。我们尝试将srand(time(0))放在函数的开头,但看起来它们都得到相同的数字。

我们是否只需要为每个程序调用{​​{1}}一次,即在srand(time(0))的开头(例如),在每个被调用多次的函数的开头,或其他什么?< / p>

7 个答案:

答案 0 :(得分:37)

srand()为随机数生成器播种。您只需在启动期间拨打srand(time(NULL))一次。

那说,文件说明:

  

函数rand() 不可重入   或线程安全的,因为它使用隐藏   在每次调用时修改的状态。   这可能只是种子价值   用于下次通话,或者可能   做一些更精细的事情。为了   在...中获得可重现的行为   线程应用程序,这个状态必须   明确。功能   rand_r()提供了一个指针   一个unsigned int,用作州。   这是一个非常少量的国家,   所以这个功能将是一个弱点   伪随机发生器。尝试   drand48_r(3)而不是。

上面强调的部分可能就是为什么你的所有主题都得到相同的数字。

答案 1 :(得分:8)

如果要同时启动所有线程,发送到srand的时间可能与每个线程相同。由于它们都有相同的种子,它们都返回相同的序列。尝试使用其他内容,例如来自局部变量的内存地址。

答案 2 :(得分:7)

来自rand手册页:

  

函数rand()不可重入或线程安全,因为它使用在每次调用时修改的隐藏状态。

所以不要将它与线程代码一起使用。如果您使用的是linux / glibc,请使用rand_r(或drand48_r)。使用不同的值为每个RNG播种(您可以在主线程中播种第一个RNG,以便为每个线程中的RNG生成随机种子)。

答案 3 :(得分:6)

当您使用C ++而不是C时,您可以通过使用c ++ 11来避免通常与srand / rand相关的线程问题。这取决于使用支持这些功能的最新编译器。您将在每个线程上使用单独的引擎和分发。 这个例子就像一个骰子。

#include <random>
#include <functional>

std::uniform_int_distribution<int> dice_distribution(1, 6);
std::mt19937 random_number_engine; // pseudorandom number generator
auto dice_roller = std::bind(dice_distribution, random_number_engine);
int random_roll = dice_roller();  // Generate one of the integers 1,2,3,4,5,6.

在回答此问题时,我提到Wikipedia C++11Boost random

答案 4 :(得分:2)

这是一个很好的问题。我不能直接回答它,因为我认为有更大的问题。 看起来rand在任何方面都是线程安全的。它保持内部状态,如果是每个进程或每个线程,它似乎没有很好地定义,如果它是线程安全的,则它是每个进程。

确保我会在每次访问时锁定互斥锁。

或者最好使用更好定义的生成,例如来自boost

的生成

答案 5 :(得分:1)

C不是为多线程而设计的,因此没有定义多线程的srand()行为,并且取决于C运行时库。

许多Unix / Linux C运行时库使用单个静态,从多个线程访问是不安全的,因此使用这些C运行时,您根本无法使用多个线程中的srand()和rand()。其他Unix C运行时可能表现不同。

Visual C ++运行时使用每线程内部状态,因此为每个线程调用srand()是安全的。但正如Neil所指出的那样,你可能会为所有线程播放相同的值 - 所以请用(time + thread-id)来播种。

当然,为了便于携带,使用Random对象而不是rand函数,然后根本不依赖于隐藏状态。你仍然需要每个线程一个对象,并且用(time + thread-id)为每个对象播种仍然是一个好主意。

答案 6 :(得分:-1)

它们都得到相同的数字,因为你可能同时启动所有线程,或者它们都使用相同的静态种子,在这种情况下你有点填充。你需要一个比time()更好的熵源。但是,快速破解的方法是使用(time * thread-id)种子,其中thread-id是每个工作线程的id。

当然,C ++中的正确​​解决方案是不使用随机数生成器函数,而是使用随机数生成器对象,如Boost随机数库提供的那些,就其本质而言(因为它们是基于堆栈的) )是线程安全的。有关示例,请参阅this answer I prepared earlier。但是,在MT程序中提供足够的熵可能仍然存在问题,因为使用time()仍然会出现我上面提到的问题。