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

多线程C程序调用rand()无法生成随机数,求解决方案

多线程C程序中rand()生成重复随机数的解决方法

我编写了如下多线程C程序,期望每个线程生成随机等待时间,但程序无法生成随机数。我已在每个线程中调用srand(time(NULL)+getpid())为rand()播种,却仍得到相同的数值输出。我了解这是因为硬件运行速度过快,时钟速度快于rand函数的播种速度导致的,希望获取让rand()生成更多不同值的可行方法。

原程序代码

#include<pthread.h>
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>
#define ERROR_CREATE       1
#define ERROR_JOIN         2

// create the function to be executed as a thread
void *thread(void *ptr)
{
    uintptr_t type = (uintptr_t) ptr; // thread number
    srand(time(NULL) + getpid());
    int wait = rand() % 10; // randomizes numbers from 0 to 9
    sleep(wait); // waits in time intervals of seconds
    printf("Thread - %ld waiting for %d seconds\n",type, wait);
    return  ptr; // returns the thread number
}

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "Error with command line arguments");
    }

    int num_threads = atoi(argv[1]);
    pthread_t threads[num_threads]; // array of thread types

    for (long i = 1; i <= num_threads; i++) {
        if (pthread_create(&threads[i], NULL, thread, (void *)i) != 0)
        {
            fprintf(stderr,"Error: could not create thread");
            return ERROR_CREATE;
        }
    }
        // terminate each thread assigned
    for (int i = 1; i <= num_threads; i++) {
        if (pthread_join(threads[i], NULL) != 0)
        {
            fprintf(stderr, "Error: could not terminate thread");
            return ERROR_JOIN;
        }
    }

    return 0;
}

可行解决方法

1. 主线程统一播种,线程内用互斥锁保护rand()

rand()本身不是线程安全的,多线程同时调用会导致竞态,但如果在主线程启动前只播种一次,再用互斥锁控制rand()的访问,可以避免重复种子问题:

修改后的核心代码:

#include<pthread.h>
// ... 其他头文件不变

pthread_mutex_t rand_mutex; // 全局互斥锁

void *thread(void *ptr)
{
    uintptr_t type = (uintptr_t) ptr;
    int wait;
    
    pthread_mutex_lock(&rand_mutex);
    wait = rand() % 10;
    pthread_mutex_unlock(&rand_mutex);
    
    sleep(wait);
    printf("Thread - %ld waiting for %d seconds\n",type, wait);
    return ptr;
}

int main(int argc, char **argv) {
    // ... 参数检查逻辑不变
    
    srand(time(NULL)); // 主线程提前播种
    pthread_mutex_init(&rand_mutex, NULL); // 初始化互斥锁
    
    int num_threads = atoi(argv[1]);
    pthread_t threads[num_threads];
    
    // 修正数组索引越界问题:从0开始循环
    for (long i = 0; i < num_threads; i++) {
        if (pthread_create(&threads[i], NULL, thread, (void *)(i+1)) != 0)
        {
            fprintf(stderr,"Error: could not create thread\n");
            return ERROR_CREATE;
        }
    }
    
    for (int i = 0; i < num_threads; i++) {
        if (pthread_join(threads[i], NULL) != 0)
        {
            fprintf(stderr, "Error: could not terminate thread\n");
            return ERROR_JOIN;
        }
    }
    
    pthread_mutex_destroy(&rand_mutex);
    return 0;
}

2. 每个线程使用独立随机数状态(推荐)

使用POSIX标准的rand_r()函数,每个线程维护自己的种子,避免多线程共享状态的问题。给种子加入线程编号,确保即使同一时间创建线程,种子也不重复:

修改后的线程函数:

void *thread(void *ptr)
{
    uintptr_t type = (uintptr_t) ptr;
    // 种子组合时间、进程ID、线程编号,保证唯一性
    unsigned int seed = time(NULL) + getpid() + type;
    int wait = rand_r(&seed) % 10;
    
    sleep(wait);
    printf("Thread - %ld waiting for %d seconds\n",type, wait);
    return ptr;
}

3. 使用现代线程安全随机数API

直接调用无需手动播种、天生线程安全的随机数函数,比如BSD/macOS下的arc4random_uniform(),或者Linux下的getrandom():

// 使用arc4random_uniform的例子,直接生成0-9的随机数
int wait = arc4random_uniform(10);

额外注意点

  • 原程序中threads[num_threads]数组从索引1开始赋值会导致越界,需修正为从0开始循环。
  • rand() % 10生成的是0到9的整数,并非0到10,若需要包含10,应改为rand() % 11。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:15:32