当我用OMP(C++)生成随机数时,有一个奇怪的问题



代码如下:

#include<omp.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
unsigned int seed = 1;
int n =4;
int i = 0;
#pragma omp parallel for num_threads(4) private(seed)
for(i=0;i<n;i++)
{
int temp1 = rand_r(&seed);
printf("nRandom number: %d by thread %dn", temp1, omp_get_thread_num());
}
return 0;
}

代码输出为:

Random number: 1905891579 by thread 0
Random number: 1012484 by thread 1
Random number: 1012484 by thread 2
Random number: 1012484 by thread 3

这对我来说很奇怪:为什么线程0有不同的编号?但是当我用常数4改变n时:

#include<omp.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
unsigned int seed = 1;
const int n =4;
int i = 0;
#pragma omp parallel for num_threads(4) private(seed)
for(i=0;i<n;i++)
{
int temp1 = rand_r(&seed);
printf("nRandom number: %d by thread %dn", temp1, omp_get_thread_num());
}
return 0;
}

代码输出为:

Random number: 1012484 by thread 2
Random number: 1012484 by thread 3
Random number: 1012484 by thread 0
Random number: 1012484 by thread 1

所有线程都有相同的随机数。当n不是常量变量时,线程0有不同的数字,我不明白为什么。有人知道这件事吗?非常感谢。

seed被声明为private,因此在循环中它没有初始化值,更重要的是,每个实例可能有也可能没有不同的值,其值的使用是UB。您可以使用firstprivate让私有实例初始化为原始值。

#pragma omp parallel for num_threads(4) firstprivate(seed)

此外,rand_r不是一个标准函数,而是一个2级线程安全的POSIX函数。级别2意味着rand_r只有在单独的对象/数据源上使用时才是安全的——这里的情况并非如此——我会使用相同的种子计数器。在这种情况下,被调用的线程的顺序是不确定的和不同步的。奇数输出是可能的,因为任何一个线程都有机会在其他线程之前更新种子的值。

问题是未初始化声明为private的变量。如果您添加此行

printf("thread %d seed %u n", omp_get_thread_num(), seed);

int temp1 = rand_r(&seed)之前,你会得到这样的输出:

thread 3 seed 0 
Random number: 1012484 by thread 3 seed 2802067423
thread 0 seed 21850 
Random number: 2082025184 by thread 0 seed 2464192641
thread 2 seed 0 
Random number: 1012484 by thread 2 seed 2802067423
thread 1 seed 0 
Random number: 1012484 by thread 1 seed 2802067423

重复运行,在我的机器上,我看到线程0总是获得不同的seed值,而其他线程具有seed=0。在任何情况下,这都是由于未初始化的变量导致的UB。

最新更新