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

时间:2012-09-19 07:35:17

标签: c openmp

我正在使用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以上面以粗体显示的顺序运行迭代。

2 个答案:

答案 0 :(得分: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
    ...
}

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

答案 1 :(得分:2)

如果我们希望OpenMP线程按顺序执行,我们必须使用ordered子句。但是我们必须小心。以下内容将按顺序(ii打印到0,从19打印0&#39; s(和广告ID) } 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());

输出(在我的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