下面的代码(并且可以按原样编译)导致随机数生成器由于某种原因为所有进程返回相同的随机数。怎么会这样?我是否在使用互斥锁做错了什么?
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define RETURN_FAILURE_IF_TRUE(condition, ...) \
{ \
if(condition) \
{ \
fprintf(stderr, __VA_ARGS__); \
return EXIT_FAILURE; \
} \
}
#define RETURN_FAILURE_IF_FALSE(condition, ...) \
RETURN_FAILURE_IF_TRUE(!(condition), __VA_ARGS__)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int nextRandomDouble(double* d)
{
if(pthread_mutex_lock(&mutex) != 0) return 0;
*d = drand48();
if(pthread_mutex_unlock(&mutex) != 0) return 0;
return 1;
}
int main()
{
const int processes = 5;
srand48(time(NULL));
for(int i = 0; i < processes; ++i)
{
pid_t pid = fork();
RETURN_FAILURE_IF_TRUE(pid < 0, "Fork failed.\n");
if(pid == 0)
{
double d;
RETURN_FAILURE_IF_FALSE(nextRandomDouble(&d), "PRNG failed.\n");
printf("rnd: %f\n", d);
return EXIT_SUCCESS;
}
}
for(int i = 0; i < processes; ++i)
{
int status;
pid_t pid = waitpid(-1, &status, 0);
RETURN_FAILURE_IF_TRUE(
(pid != 1) && (status != 0), "Child exit failed.\n"
);
}
return EXIT_SUCCESS;
}
答案 0 :(得分:3)
srand48(time(NULL));
您可以在流程开始时将每个流程中的PRNG播种到第二个流程。这意味着在相同的第二个种子中开始的所有进程都使PRNG具有相同的值。
尝试:
srand48((getpid()*2654435761U)^time(NULL));
答案 1 :(得分:1)
您在每个进程中获得相同的随机数序列,因为您在调用fork()
之前为PRNG播种。在调用fork()
之后,每个进程都有它自己的PRNG 副本,接种到相同的值 - 所以当然每个进程都会获得相同的数字序列。
请注意,互斥锁调用是不必要的,因为在fork()
每个进程在其自己的虚拟地址空间中运行之后 - 这里的进程之间没有共享状态。
如果您使用pthread_create()
代替fork()
,创建单独的线程,则线程将共享PRNG状态,并且每个线程将获得与PRNG序列不同的值:
void *thread_func(void *arg)
{
double d;
if (!nextRandomDouble(&d))
fprintf(stderr, "PRNG failed.\n");
else
printf("rnd: %f\n", d);
return 0;
}
int main()
{
const int processes = 5;
pthread_t thread[processes];
srand48(time(NULL));
for(int i = 0; i < processes; ++i)
{
int pthread_err = pthread_create(&thread[i], NULL, thread_func, NULL);
RETURN_FAILURE_IF_TRUE(pthread_err != 0, "pthread_create failed.\n");
}
for(int i = 0; i < processes; ++i)
{
void *status;
int pthread_err = pthread_join(thread[i], &status);
if ((pthread_err != 0) || (status != 0))
fprintf(stderr, "Child exit failed.\n");
}
return EXIT_SUCCESS;
}
答案 2 :(得分:0)
在多线程环境中使用drand48
是一个坏主意。这是在调用之间使用共享的全局状态。因此,要么线程踩在彼此的脚上(如果这不是线程安全的话),要么轮流等待(如果访问是互斥的,就像你做的那样)。
请改用erand48
。这会在参数中接收您应该为每个线程初始化为不同值的状态。