为什么rand()在fork之后不是那么随机?
#include #include #include #include int main() { int i =10; /* initialize random seed: */ srand(time(NULL)); while(i--){ if(fork()==0){ /* initialize random seed here does not make a difference: srand(time(NULL)); */ printf("%d : %d\n",i,rand()); return; } } return (EXIT_SUCCESS); }
打印相同(每次运行时不同)数量10次 – 预计? 我有一个更复杂的代码片段,每个分叉的进程依次运行 – 没有区别
输出必须相同。 如果两个进程每个都使用相同的种子对随机数进行种子处理,并且每次调用rand
一次,则它们必须得到相同的结果。 这就是拥有种子的重点。 所有进程都使用相同的种子调用srand
(因为你只调用一次srand
)并且它们都调用rand
一次,所以它们必须得到相同的结果。
取消注释srand
不会产生任何影响,因为除非秒数已经改变,否则它们仍将提供相同的种子。 你可以这样做:
srand(time(NULL) ^ (getpid()<<16));
rand()
函数是一个伪随机数生成器。 这意味着生成的数字序列是确定性的,仅取决于提供的种子。
因为您要将相同的进程分叉10次,所以随机数生成器的状态对于每个子进程都是相同的。 下次调用rand()
您将获得相同的值。
通过在子进程内调用srand(time(NULL))
,你可能会有所帮助,但time()
的粒度只有1秒,所以你的所有孩子都可能在同一秒内开始。 具有相同值的播种生成相同的伪随机序列。
您可以尝试使用取决于子编号的值进行种子设定:
srand(time(NULL) - i*2);
(如果time()
在fork循环期间前进1秒,我使用i*2
)
如果你的代码运行得足够快,那么srand()
可能会为每个fork提供完全相同的时间。 time()
每秒只会改变一次。
甚至添加srand(time(NULL));
(循环内部的if
块中的行)你在循环中没有区别是因为现代计算机可以非常快速地执行整个块,并且time
以秒计。 从手册页:
time()返回自Epoch以来的秒数…
如果你加一个sleep(1);
在while
循环中的if
语句之后并取消注释srand
调用,结果将是不同的,因为time
现在将返回不同的值,因为已经过了一秒。
然而,使用不同的种子值而不是等待更合适。 像i
这样的东西是个好主意,因为它对循环的每次迭代都是唯一的。
这样做的原因是因为所有程序都以相同的值播种(在while循环之外)。 一旦你分叉了新程序,你应该再次播种,否则两者都会生成相同的序列。
当你进行子进程时,你不会重新播种。 随机数发生器的状态完全相同。
即使您再次在您的孩子中播种,您也会以+/- 1秒的粒度播种。 当你分叉时,一切都发生在不到一秒钟。
尝试用不同的东西和更随机的东西播种。
这解决了这个问题:
srand48((long int)time(NULL)); i= (lrand48()/rand()+1) % 123
我没有用fork测试过,但是在一个用于调用100次的内部它可以工作。
种子与pid号码。 这有点但很难解决问题。
这是在一些页面:“这工作srand(time(0)+ getpid());但我不得不在案例0即子进程”中调用它。