现在的位置: 首页 > 综合 > 正文

Srand函数

2013年08月21日 ⁄ 综合 ⁄ 共 1855字 ⁄ 字号 评论关闭

问题描述】
在主线程里面srand()了一次,然后在线程函数里面使用rand(),可是每个线程rand出来的数列顺序一样,而且每次运行都一样。结构如图所示:
da646bd79c1fd6f6a144dfa0.jpg
func1出来的序列是1,7,4,0,9,4,8……
func2出来的序列是1,7,4,0,9,4,8……

【讨论】
网上有人说这是因为main的seed是time,而两个线程是几乎并发开始的,它们继承了main的seed,因此输出序列相同。
【证伪】
[1]将main中的随机种子设为srand(1),其余不做改变。两个线程输出结果仍旧是1,7,4,0,9,4,8……
这说明main中的种子与线程中并无关系。
[2]为了巩固以上假设,进行一下测试:
main中srand(time),在func1和func2里面均加上语句srand(1),输出序列均为1,7,4,0,9,4,8……
main中srand(time),在func1和func2里面均加上语句srand(time),输出序列均为2,9,4,6,8,3,7……
main中srand(1),在func1和func2里面均加上语句srand(time),输出序列均为2,9,4,6,8,3,7……
main中srand(1),在func1里加上srand(1),func2里面加上srand(time),输出序列分别为1,7,4,0,9,4,8……和2,9,4,6,8,3,7……
——由此,证明了无论main中的srand是如何的,线程中的rand结果只与该线程中的srand有关。也即,多线程编程中,在每个线程里面都要srand一次。
说明:由于如果没有显式srand,系统默认为rand(1),因此在func里面用不用该语句输出都一样。当然,如果两个线程中都srand了time,由于它们并发运行,也就是说执行srand的时候它们的time相同,即种子相同,从而输出序列相同。

【问题解决】
如何做到不同线程中的数从横向上看来也不同呢?
先从rand的伪随机性说起。
我们都说rand是伪随机的,是因为它有章可循,并不是真的“随机”。它是以某个线性同余的递推公式推算出来的一些列数,当这系列数很大的时候,它们就符合正态分布。这个递推公式类似于:
y=ax+b(mod   n),其中,a、n一般是大素数,而a、b、n都是常数,因此rand的产生决定于x,而且下一个y是上一次产生的y的函数。
-----------------------------------------------------------------------
比如VC中对于rand()函数是如下实现的:
int   __cdecl   rand   (void)   
{  return(((holdrand   =   holdrand   *   214013L   +   2531011L)   >>   16)   &   0x7fff);   }
-------------------------------------------------------------------------
而srand()的函数是如下实现的:
void __cdecl srand (unsigned int seed)
{
  #ifdef _MT 
    _getptd()->_holdrand = (unsigned long)seed;  
  #else /* _MT */
   holdrand = (long)seed;
  #endif /* _MT */
}
-------------------------------------------------------------------------
递推公式意味着,确定的输入产生确定的输出,而且顺序是不变的。因此,当我们设置srand()的时候,相当于设置了递推公式的数列起点,从x开始计算y。因此,srand的种子相同相当于起点相同,数列相同也就可以理解了。
那么,如果要让两个数列不同,只需要srand的时候使用不同seed就可以了。可以采取以下方法:
1)在外部产生随机数,然后将该数作为参数传进线程函数设为seed。
2)将线程ID作为线程的seed。
3)使用其他可以令线程拥有不同seed的方法。
*)最好不要使用time(NULL)作为每个线程的seed,因为线程开始的time(NULL)很可能相同。

转自:http://hi.baidu.com/czlaner/blog/item/c06200097c849dc63ac76344.html

抱歉!评论已关闭.