代码如下:
#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。