如何使用rand_r()在C语言中创建线程安全的随机数生成器?

3
我被要求不要使用 rand(),因为它们不是“线程安全的”,而且每次都要使用不同的种子值。我在 GitHub 上找到了一个使用以下种子值的示例:unsigned int seed = time(NULL);。这只有秒级精度,由于程序在不到1秒的时间内运行,我每次都会得到相同的随机数。
如何修改此算法,以便仅使用 rand_r() 或任何其他“线程安全”的方法生成10个随机数?
int main()
{
    for(int i = 0; i < 10; i++){
        int random;
        unsigned int seed = time(NULL);
            random = 1 + (rand_r(&seed)% 10);
        printf("%d\n",random);
    }
 return 0;
}

1
与许多类似的问题一样 - 只需种子一次。 - Oliver Charlesworth
奇怪,为什么多次种子化会导致数字完全相同? - btramisetty
2
因为rand_r是一个确定性函数,只有一个参数——seed的值。 - Oliver Charlesworth
1个回答

9
rand_r函数需要传递一个指向状态变量的指针。在第一次调用rand_r之前,它会被设置为种子值。每次调用rand_r时,您需要传递该值的地址。
为了线程安全,每个线程都需要拥有自己的状态变量。但是,您不希望为每个线程的状态变量使用相同的初始值,否则每个线程将生成相同的伪随机数序列。
您需要使用对于每个线程都不同的数据来初始化状态变量,例如线程ID、时间和/或进程ID等其它信息。
例如:
// 2 threads, 1 state variable each
unsigned int state[2];

void *mythread(void *p_mystate)
{
    unsigned int *mystate = p_mystate;
    // XOR multiple values together to get a semi-unique seed
    *mystate = time(NULL) ^ getpid() ^ pthread_self();

    ...
    int rand1 = rand_r(mystate);
    ...
    int rand2 = rand_r(mystate);
    ...
    return NULL;
}

int main()
{
    pthread_t t1, t2;

    // give each thread the address of its state variable
    pthread_create(&t1, NULL, mythread, &state[0]);
    pthread_create(&t2, NULL, mythread, &state[1]);
    ...
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}

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