随机数和多个srand调用
我正在编写一个程序,它将在循环中生成大量随机数。 我试图使这些数字更难以预测(不仅是为了安全,而是为了避免multithreading上的冲突)。
我注意到许多文档建议在程序中只调用一次srand
。 例如: C中的随机数 ,选择的答案是“作为一般规则,只在程序中调用一次srand()”。
但为什么? 做这样的事情为什么会这么糟糕:
int THIS_THREAD_SEED; int randomness() { ++THIS_THREAD_SEED; int i; for(i=0 i<1000; i++) { unsigned n = rand_r(&THIS_THREAD_SEED) / RAND_MAX; /* do something with n */ } return 0; } int do_something() { int i; for(i=0; i<1000; i++) { randomness(); } }
因此,每个函数调用一次更改种子,而不是每个程序一次。 这样,无论有多少线程在运行,没有两个线程都会有相同的随机数列表……对吗?
更新假设我为每个线程都有一个唯一的种子,或者在全局SEED上使用互斥锁来防止竞争条件。
让我们把这个问题分成两个单独的问题。
-
如果您在访问随机数生成器时担心竞争条件,请创建互斥或其他同步原语以避免这种情况。
-
如果你想多次调用
srand()
,请不要。 这背后的原因是随机生成器初始化例程,它根据种子设置变量具有更差的随机特性,比随机生成器本身的性能更差,不应该用作替代品。
srand()
将重置 rand()
将为您生成的数字流。
从srand的手册:
The srand() function sets its argument as the seed for a new sequence of pseudo-random integers to be returned by rand(). These sequences are repeatable by calling srand() with the same seed value.
如果你需要“更好”的随机数,那么rand()提供你应该查看其他随机来源。
另外srand()
不用于rand_r()
,而是使用你提供的参数(对rand_r()
)。
如果你想从多个线程使用rand_r()
,所有线程都应该有一个本地种子,你不应该使用一个全局变量。
rand()
替代品可以是Mersenne Twister
但是如果你需要“真正的”随机性,你必须寻找硬件支持。
并回答:
因此,每个函数调用一次更改种子,而不是每个程序一次。 这样,无论有多少线程在运行,没有两个线程都会有相同的随机数列表……对吗?
不,不这样做,你应该有一个线程局部的SEED变量初始化为每个线程独特的东西。 您可以对第一个种子使用time()
,然后使用该随机序列为其他线程生成种子,或者如果使用* nix,则从/dev/random
或/dev/urandom
读取4-8个字节。
希望能给出一些见解,因为这是午夜隆隆声,晚安<3
为避免竞争条件,您需要为每个线程使用单独的种子变量。 这意味着每个线程都有自己独立的随机数序列。