如何强制openMP以特定顺序运行迭代

Mic*_*ant 6 c openmp

我使用openMP并行运行模拟实例.

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

循环的一部分检查索引号为"part"的输出文件是否已经存在(因此我可以对某个"Parts"值运行模拟,然后在不覆盖现有结果的情况下增加它).但是,这需要迭代按顺序运行.也就是说,对于n个线程,它应该首先同时运行部分(1) - (n),然后是部分(n + 1) - (2n),依此类推.现在(3个线程并行运行,"parts"设置为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以上面以粗体显示的顺序运行迭代.

Hri*_*iev 7

您可以更改每个线程1schedule子句中获得的迭代块的大小,例如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
    ...
}
Run Code Online (Sandbox Code Playgroud)

希望我能正确理解你的问题.


Nik*_*kos 5

如果我们希望 OpenMP 线程按顺序执行,我们必须使用该ordered子句。然而,我们必须小心。以下将按i顺序打印(和线程 ID)(i019,从0到到omp_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());
Run Code Online (Sandbox Code Playgroud)

输出(在我的 8 核英特尔 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
Run Code Online (Sandbox Code Playgroud)

但请注意:

#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()); 
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

// 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]);
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)