通常,srand() 的播种是通过以下方式完成的:
srand(time(NULL));
在我的例子中,我使用随机数在网络运行时为我的客户端进程生成一个标识符。该进程有时会重新启动并生成一个新的标识符。随着客户端数量的增加,两个客户端很有可能在同一秒内调用 srand(time(NULL))
,这会创建两个相同的标识符,或者服务器端看到的冲突。 Some people suggested a finer resolution :
srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
但这里的问题是种子会每24天左右重复一次,当机器数量足够多时,仍然有碰撞的机会。 There's another solution :
srand(time.tv_usec * time.tv_sec);
但这对我来说似乎也有问题,因为该乘积的模数(高位溢出并被放弃)在 unsigned int
种子值的范围内分布不均。例如,对于每一秒,time.tv_usec == 0
都会产生相同的种子。
那么在我的案例中有没有办法为 srand() 播种?
编辑:客户端在 Linux、Windows、Android 和 iOS 上运行,因此 /dev/random
或 /dev/urandom
并不总是可用。
附言我知道 GUID/UUID 方法,但我想知道在这种情况下是否可以正确地播种 srand()。
最佳答案
srand
和 rand
如果您有许多进程或线程需要在它们之间具有独立的伪随机性,则根本不合适。
在 POSIX 系统上,您可以使用 rand48
函数系列,例如具有已知状态大小的 jrand48
。如果你依赖于进程、线程和机器独立性,你应该使用进程 ID、线程 ID、IP 地址和时间中的有效位来初始化状态。 jrand[48]
采用(并修改)三个 short
的状态,因此用不同的数量来播种它们应该相对简单。
除了您列出的一个系统外,其他所有系统都是 POSIX,所以这应该在那里工作。我不知道什么才是适合 Windows 系统的后备方案。
关于c - 如何播种 srand() 以避免在大量机器上发生冲突?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21020418/