这些天我在学习OpenMP,我刚刚满足了"threadprivate"指令。下面由我自己编写的代码片段没有输出预期的结果:
// **** File: fun.h **** //
void seed(int x);
int drand();
// ********************* //
// **** File: fun.c **** //
extern int num;
int drand()
{
num = num + 1;
return num;
}
void seed(int num_initial)
{
num = num_initial;
}
// ************************ //
// **** File: main.c **** //
#include "fun.h"
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int num = 0;
#pragma omp threadprivate(num)
int main()
{
int num_inital = 4;
seed(num_inital);
printf("At the beginning, num = %dn", num); // should num be 4?
#pragma omp parallel for num_threads(2) schedule(static,1) copyin(num)
for (int ii = 0; ii < 4; ii++) {
int my_rank = omp_get_thread_num();
//printf("Before processing, in thread %d num = %dn", my_rank,num);
int num_in_loop = drand();
printf("Thread %d is processing loop %d: num = %dn", my_rank,ii, num_in_loop);
}
system("pause");
return 0;
}
// ********************* //
下面列出我的问题:
为什么
printf("At the beginning, num = %dn", num);
的结果是num = 0
而不是num = 4
?对于并行for循环,多次执行会产生不同的结果,其中之一是:
Thread 1 is processing loop 1: num = 5
Thread 0 is processing loop 0: num = 6
Thread 1 is processing loop 3: num = 7
Thread 0 is processing loop 2: num = 8
似乎在for循环中num
被初始化为4,这表示copyin
子句中的num
等于4。为什么printf("At the beginning, num = %dn", num)
中的num
与copyin
中的不同?
在OpenMP网站上,它说
在并行区域中,主线程对遇到并行区域的线程中变量副本的引用。
根据这个解释,线程0(主线程(应该首先包含
num = 4
。因此,循环0的输出应该始终为:Thread 0 is processing loop 0: num = 5
。为什么上面的结果不同?
我的工作环境是带有VS2015的win10操作系统。
我认为问题出在fun.c
编译单元内。编译器无法确定extern int num;
变量也是TLS变量。
我将在这个文件中包括指令#pragma omp threadprivate(num)
:
// **** File: fun.c **** //
extern int num;
#pragma omp threadprivate(num)
int drand()
{
num = num + 1;
return num;
}
void seed(int num_initial)
{
num = num_initial;
}
// ************************ //
在任何情况下,编译器都应该在链接阶段对此发出警告。
copyin
子句用于OpenMP团队(例如计算加速器上的计算(。
事实上,OpenMP文档中写道:
这些子句支持将数据值从一个隐式任务或线程上的private或threadprivate变量复制到团队中其他隐式任务和线程上的相应变量。
因此,在您的情况下,您应该使用子句firstprivate
。
请注意,VS2015可能不支持您正在阅读的OpenMP文档的版本(5.0(。我建议您阅读与VS2015兼容的旧版本。编译程序的结果可能是未定义的。