我在VS2008中有以下代码:
int i,j;
bool pr = false;
#pragma omp parallel for private(pr) num_threads(2)
for(i=0;i<PIC_X;i++)
{
int rank = omp_get_thread_num();
int count = omp_get_num_threads();
if ( !pr )
{
printf_s("Hello from thread %d of %d\n", rank, count);
pr = true;
}
for(j=0;j<PIC_Y;j++)
{
// do stuff
}
}
(如果你想知道的话,不要试图建立一个嵌套的OpenMP循环)。问题是,num_threads子句无论如何都没有效果:我只在输出中得到“来自0的线程0的Hello”。我也尝试使用omp_set_num_threads(2)
,但无济于事。是什么给了什么?
答案 0 :(得分:4)
您已将pr设置在并行区域之外,然后通过将其置于私有子句中使其成为私有。这意味着每个线程都有一个pr,但私有pr变量没有初始化。对pr使用firstprivate而不是private,以便初始化私有变量。
但是,默认情况下,循环计数器是私有的是不正确的。用于工作共享(或规范)的循环计数器(即变量i)是私有的(对于OMP V2.0规范的构造,第2.4.1节)。但“j”不是。请参阅OpenMP V2.0规范(Microsoft在VS2008中支持的规范),第2.7.2节“数据共享属性子句”:
如果遇到并行或工作共享结构时变量可见,并且 该变量未在共享属性子句或threadprivate中指定 指令,然后共享变量。在动态内声明的静态变量 共享区域的范围。堆分配内存(例如,使用 C或C ++中的malloc()或C ++中的new运算符)是共享的。 (指向此的指针 但是,内存可以是私有的,也可以是共享的。)具有自动存储的变量 在并行区域的动态范围内声明的持续时间是私有的。
至于omp_get_num_threads()返回1,我能想到的是你没有使用OpenMP标志编译它。
答案 1 :(得分:1)
如果OpenMP将外部循环拆分为2(即一个进程获得0..PIC_X / 2)而另一个进程获得后半部分,则只有一个进程会看到i == 0.
如果您的图像像我看到的所有图像一样被组织,外部循环应为Y,内部循环应为X,内部循环应为OpenMP,因为这就是图像在内存中的组织方式。