我有几个线程都运行相同的功能。在每个中,它们会多次生成不同的随机数。我们尝试将srand(time(0))
放在函数的开头,但看起来它们都得到相同的数字。
我们是否只需要为每个程序调用{{1}}一次,即在srand(time(0))
的开头(例如),在每个被调用多次的函数的开头,或其他什么?< / p>
答案 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++11和Boost 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()仍然会出现我上面提到的问题。