为一批程序生成随机数种子

3

通常我会使用类似以下代码:

srand(time(0));

为了获得每次程序调用时都会改变的伪随机性。然而,我现在面临一个批量启动所有程序的情况,由于“时间”仅在每秒钟改变一次,因此大多数时候,所有程序都使用相同的种子开始运行。
当我想让一堆程序同时启动并获得不同的种子时,有更好的种子生成策略吗?

使用更细的时间粒度计时器(例如系统纳秒计数器),并将其与进程ID混合。但对于安全应用程序或蒙特卡罗模拟仍然不够好。 - Mark Lakata
1
使用 rdtsc https://dev59.com/_Gsz5IYBdhLWcg3w2Llt#7617612,它是自处理器通电以来的伪周期数。如果您需要更多保证,请将其与 PID 进行异或运算。 - phuclv
3个回答

7
使用 srand(time(0) ^ getpid()) 来通过进程特定值对种子进行排列。这将确保在同一秒内启动的进程具有不同的种子。请注意,不要在任何“重要”的事情中使用它,例如涉及密码学或真实货币。
排列是使用“异或”或XOR运算符'^'完成的。由于我们知道在同一时间运行的两个进程必须具有不同的进程ID,因此通过将time(0)的响应与当前PID异或,我们可以确保两个不同的进程不会具有完全相同的种子。
请注意,这只是一个非常弱的保证,因为我们只扭曲了几位。如果时间恰好增加了一秒,并且进程ID恰好增加了一个,在某些情况下,您将得到相同的种子。
如果您需要真正不同的随机数种子,则需要从 /dev/random 读取4个字节,然后将其用作整数以使您的 RNG 种子。
再次强调,请不要将此随机数序列用于任何“重要”的事情。我指的是超过简单的 Monte-Carlo 模拟或石头剪刀布游戏。

喜欢它。也许可以更深入地了解异或如何工作以创建新的独特值。+1 - Brian Tracy
如果您有一个合适的库,可以使用像SHA-1这样的安全哈希函数来将当前时间和进程ID号制作成RNG种子。如果RNG真的很好,我想这不会有影响,但我有点担心各种PID值只会相差几个位。安全哈希函数确实可以很好地处理散列,即使输入上只有一个比特的差异也会导致输出上的大差异。这可能对于RNG系列的每个值都使用太耗时了,但仅用于种子可能应该没问题。 - steveha
1
即使您使用SHA-1生成种子,您的熵也不会比对time()和getpid()的基本调用更高,因此做任何更复杂的事情都是浪费精力。如果OP要使用srand/random,则最好从/dev/random中获取种子。 - caskey
对于 time(0) ^ getpid() 的合理且简单的解决方案加1。然而,它确实存在一些问题,因为 gid 有一定的可预测性,当然 time(0) 也是如此。也许如果每个程序都有自己在代码中固定的随机值:time(0) ^ getpid() ^ my_program_mask。我想,归根结底,每个程序都需要调用一个真正随机的源。 - chux - Reinstate Monica
这太棒了。对于我的使用,我实际上只需要getpid(),完全可以不用随机数(我只需要一个来回翻转的位),但如果将来有人发现这个问题,这个答案会更加完整。 - pjreddie

1
你可以将time(0)与其他特定于程序的值结合使用。例如,将其与程序名称的良好哈希值(argv[0]通常足够)异或,甚至只是(最好是哈希值)进程ID的异或(如果它们在同一主机上启动,否则进一步与主机名或IP的哈希值异或)。您甚至可以使用UUID的哈希值。
注意:仅与进程ID异或非常薄弱-如果进程启动时第二个滴答声响起,则时间值中翻转的位很容易与两个进程ID之间不同的位匹配,使生成的种子相同。话虽如此,根据您有多少理由关心,投入相应的努力...

0
也许你需要使用getpid()以及一些亚秒时间(也许是整秒时间)。也许制作一个值的MD5哈希,并使用它?使用getpid()保证您使用的数据部分对于每个进程都是唯一的,但本身并不给您很多随机性。当然,使用rand()几乎不能保证是一个好的随机数生成器。您肯定不能将其用于加密。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接