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

srand无效?

2013年02月15日 ⁄ 综合 ⁄ 共 1408字 ⁄ 字号 评论关闭

程序在启动后,初始化的时候正确调用了srand(time(NULL)). 但是在之后使用的地方,rand() 得到的随机数序列,每次程序运行都是一致的。也就是srand()根本没起作用。更进一步调试,把srand注释掉,得到的随机数序列是一致的。这就奇怪了。
调了半天,没啥进展,跟进srand的实现看看:

void __cdecl srand (    unsigned int seed       )
{
        _getptd()->_holdrand = (unsigned long)seed;
}

这部分代码很简单,直接设置一下。问题是这个_getptd()是个什么东西。原来是个包装函数:

_ptiddata __cdecl _getptd (       void        ) 
{
        _ptiddata ptd = _getptd_noexit();
        if (!ptd) {
            _amsg_exit(_RT_THREAD); /* write message and die */
        }
        return ptd;
}

继续跟_getptd_noexit(),在这个函数里面,真相大白了。原来这个是获得当前thread相关的data指针:

/** _ptiddata _getptd(void) - get per-thread data structure for the current thread

换句话说,srand的时候,仅仅是把种子设置到当前线程的数据块中。这是线程相关的(就像一个ThreadLocal)。如果之后调用rand()是在另外一个线程中,那么还是默认的随机数种子。这就是这个bug的原因:srand() 和 rand() 发生在不同的线程中。

最后确认一下rand()函数:

int __cdecl rand (        void        )
{
        _ptiddata ptd = _getptd();
        return( ((ptd->_holdrand = ptd->_holdrand * 214013L
            + 2531011L) >> 16) & 0x7fff );
}

果然是从当前线程的数据中获得种子,然后算出一个伪随机数。
最后自己写段程序确认下这个问题:

void run(void *) {
   printf("thread: %d %d %d\n", rand(), rand(), rand());
   srand(123);
   printf("thread: %d %d %d\n", rand(), rand(), rand());
}
int main(int argc, char* argv[]) {
   printf("main: %d %d %d\n", rand(), rand(), rand());
   srand(123);
   printf("main: %d %d %d\n", rand(), rand(), rand());
   _beginthread(run, 0, NULL);
   getchar();
}

运行结果:
main: 6334 18467 41                                                                           
main: 23075 19053 440                                                                         
thread: 6334 18467 41                                                                         
thread: 23075 19053 440 
与预期相符。第一行,第三行分别是主函数与线程函数中输出的随机数。这时主线程与子线程均未调用srand,按默认的输出,结果一样。
第二行,第四行,主线程与子线程均已设置srand(123),则输出新的序列。

抱歉!评论已关闭.