You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子进程生成相同随机值的原因及解决方法

问题:子进程生成的随机值全部相同,如何解决?

我想要为每个子进程分配不同的随机变量,例如子进程1得到0.515,子进程2得到0.911。我尝试了以下代码:

#define _POSIX_C_SOURCE 199309L

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>


double random()
{
    double x = rand() / (double)RAND_MAX;
    return x;
}


int main()
{
    int N = 10;
    pid_t pids[N];
    
    for (int i = 0; i < N; ++i)
    {
        if ((pids[i] = fork()) < 0)
        {
            printf("Error using fork().\nExiting...\n");
            exit(-1);
        }
        else if (pids[i] == 0)
        {
            // get random value
            double result = random();
            printf("Child %d PID = %d. random() = %f.\n", i, getpid(), result);
            exit(0);
        }
    }
   
    while (N > 0)
    {
        wait(NULL);
        N--;
    }
   
    printf("Done.\n");
    return EXIT_SUCCESS;
}

运行后得到如下输出:

子进程 0 PID = 6531. random() = 0.840188.
子进程 1 PID = 6532. random() = 0.840188.
子进程 2 PID = 6533. random() = 0.840188.
子进程 3 PID = 6534. random() = 0.840188.
子进程 4 PID = 6535. random() = 0.840188.
子进程 5 PID = 6536. random() = 0.840188.
子进程 6 PID = 6537. random() = 0.840188.
子进程 7 PID = 6538. random() = 0.840188.
子进程 8 PID = 6539. random() = 0.840188.
子进程 9 PID = 6540. random() = 0.840188.
Done.

可以看到所有子进程的随机值都相同,但我希望它们各自拥有不同的值。请问为什么会出现这种情况,如何解决?


解答

原因分析

rand()函数依赖一个内部的伪随机数生成器状态,默认情况下这个状态在程序启动时会被初始化为固定值(通常是1)。当调用fork()创建子进程时,子进程会完全复制父进程的内存空间,包括伪随机数生成器的当前状态。由于所有子进程在创建时都继承了同一个未被修改过的随机状态,调用rand()时自然会生成完全相同的数值。

另外需要注意:你自定义的random()函数和标准库的random()重名了,这会导致未定义行为,建议重命名你的函数,比如改成get_random_double()。

解决方法

有两种常见的正确做法:

方法1:在每个子进程中单独初始化随机种子

在子进程调用rand()之前,用srand()初始化随机种子。可以用子进程的PID(getpid())作为种子,因为每个子进程的PID是唯一的:

修改子进程的代码块:

else if (pids[i] == 0)
{
    // 用当前子进程的PID初始化随机种子
    srand(getpid());
    // 重命名后的函数
    double result = get_random_double();
    printf("Child %d PID = %d. random() = %f.\n", i, getpid(), result);
    exit(0);
}

方法2:父进程提前生成所有随机值,传递给子进程

如果需要更严格的随机性控制,可以在父进程中先生成所有需要的随机数,然后通过管道、共享内存或者直接利用子进程继承内存的特性传递:

修改父进程代码:

// 父进程提前生成随机数
double random_vals[N];
// 父进程先初始化种子
srand(time(NULL));
for (int i = 0; i < N; ++i) {
    random_vals[i] = get_random_double();
}

for (int i = 0; i < N; ++i)
{
    if ((pids[i] = fork()) < 0)
    {
        printf("Error using fork().\nExiting...\n");
        exit(-1);
    }
    else if (pids[i] == 0)
    {
        printf("Child %d PID = %d. random() = %f.\n", i, getpid(), random_vals[i]);
        exit(0);
    }
}

这种方式的优点是随机序列完全由父进程控制,避免了子进程单独初始化可能带来的潜在问题(比如极端场景下PID重复,但实际中几乎不会发生)。

额外注意事项

  • 不要在父进程中调用srand()后立即批量创建子进程,因为如果创建速度过快,可能会出现多个子进程继承同一个已更新的随机状态,导致生成的随机数仍然重复(概率极低)。
  • 建议使用更现代的随机数API,比如Linux的getrandom()、BSD的arc4random(),这些API不需要手动初始化种子,且随机性更好。

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:52:17