8

我正在使用 openMP 并行运行我的模拟实例。

#pragma omp parallel for private(part) shared(P,lfcc,temp)
for (part = 0; part < P->Parts; part++)

循环的一部分检查索引号为“part”的输出文件是否已经存在(因此我可以针对“Parts”的某个值运行模拟,然后在不覆盖现有结果的情况下增加它)。但是,这需要迭代按顺序运行。也就是说,对于 n 个线程,它应该首先同时运行部分 (1)-(n),然后是部分 (n+1)-(2n),依此类推。现在(3个线程并行运行,并且“部分”设置为N),行为不同,运行第一部分(0),(N / 3),(2N / 3),然后是(1),(N /3+1),(2N/3+1) 等等。

现在假设,我最初想要全部完成的 30 个部分。然后我决定我需要更多零件并将“零件”更改为 45。然后第一个线程得到零件 (1)-(15)、第二个 (16)-(30) 和第三个 (31-45)。前两个线程很快发现它们所有分配的部分都已经完成,并将让最后一个线程单独工作(如果我在程序终止之前放置了一个屏障子句)。

一种简单的解决方案是让“part”变量不是从 0 开始,而是从 m+1 开始,其中 m 是先前完成的部分的数量。但我想知道是否可以强制 openMP 以上面粗体显示的顺序运行迭代。

4

2 回答 2

7

1您可以更改每个线程在schedule子句中到达的迭代块的大小,例如schedule(static,1). 使用 3 个线程,第一个线程将处理迭代 0、3、6、9 等,第二个线程将处理迭代 1、4、7、10 等,第三个线程将处理迭代 2、5、8, 11 以此类推。您仍然需要在循环中的某个位置进行同步,因为无法保证线程会同时以相同的速度执行所有步骤(您可以在每次迭代结束时设置屏障以在下一个迭代块开始之前进行同步)。

另一种解决方案是使用 OpenMP 任务构造。有了它,您可以在一个线程中运行一个大循环,生成计算任务。您可以在此循环中检查输出文件是否存在,并仅在需要时创建新任务(例如,输出文件不存在):

#pragma omp parallel
{
    ...
    #pragma omp single
    for (part = 0; part < P->Parts; part++)
    {
        if (!output_file_exists(part))
           #pragma omp task
           {
              ... computation for that part ...
           }
    }
    #pragma omp taskwait
    ...
}

希望我已经正确理解了您的问题。

于 2012-09-19T08:19:00.077 回答
6

如果我们希望 OpenMP 线程按顺序执行,我们必须使用该ordered子句。但是,我们必须小心。以下将按i顺序打印(和线程ID)(i019,tid从0omp_get_num_threads() - 1):

#pragma omp parallel
#pragma omp for ordered
for (i = 0; i < 20; i++)
    #pragma omp ordered
    printf("i=%d - tid=%d\n", i, omp_get_thread_num());

输出(在我的 8 核 intel x86_64 机器中):

i=0 - tid=0
i=1 - tid=0
i=2 - tid=0
i=3 - tid=1
i=4 - tid=1
i=5 - tid=1
i=6 - tid=2
i=7 - tid=2
i=8 - tid=2
i=9 - tid=3
i=10 - tid=3
i=11 - tid=3
i=12 - tid=4
i=13 - tid=4
i=14 - tid=5
i=15 - tid=5
i=16 - tid=6
i=17 - tid=6
i=18 - tid=7
i=19 - tid=7

但请注意:

#pragma omp parallel
#pragma omp for ordered
for (i = 0; i < 20; i++)
{
    // the threads enter this for() section in order but won't 
    // print this statement in order!
    printf("other i=%d - tid=%d\n", i, omp_get_thread_num());
    #pragma omp ordered
    // these are printed in order
    printf("i=%d - tid=%d\n", i, omp_get_thread_num()); 
}

输出:

other i=16 - tid=6
other i=18 - tid=7
other i=12 - tid=4
other i=0 - tid=0
i=0 - tid=0
other i=1 - tid=0
i=1 - tid=0
other i=2 - tid=0
i=2 - tid=0
other i=3 - tid=1
other i=6 - tid=2
other i=14 - tid=5
i=3 - tid=1
other i=4 - tid=1
i=4 - tid=1
other i=5 - tid=1
i=5 - tid=1
i=6 - tid=2
other i=7 - tid=2
i=7 - tid=2
other i=8 - tid=2
i=8 - tid=2
other i=9 - tid=3
i=9 - tid=3
other i=10 - tid=3
i=10 - tid=3
other i=11 - tid=3
i=11 - tid=3
i=12 - tid=4
other i=13 - tid=4
i=13 - tid=4
i=14 - tid=5
other i=15 - tid=5
i=15 - tid=5
i=16 - tid=6
other i=17 - tid=6
i=17 - tid=6
i=18 - tid=7
other i=19 - tid=7
i=19 - tid=7

最后请注意,这个数组是按顺序填充的:

// threads filling up array
int Arr[20] = {0};
#pragma omp parallel for ordered
for (i = 0; i < 20; i++)
    Arr[i] = i;

printf("\n\n");
// lets check to see if threads have put values to the array in order
for (i = 0; i < 20; i++)
    printf("Arr[%d]=%d\n", i, Arr[i]);

输出:

A[0]=0
A[1]=1
A[2]=2
A[3]=3
A[4]=4
A[5]=5
A[6]=6
A[7]=7
A[8]=8
A[9]=9
A[10]=10
A[11]=11
A[12]=12
A[13]=13
A[14]=14
A[15]=15
A[16]=16
A[17]=17
A[18]=18
A[19]=19
于 2017-07-29T13:53:35.260 回答