【问题标题】:openmp ordering critical sectionsopenmp 排序关键部分
【发布时间】:2015-01-27 17:43:28
【问题描述】:

我正在尝试创建一个将依次迭代循环的 OpenMP 程序。我意识到线程不适用于顺序程序——与单线程相比,我试图获得一点加速,或者至少保持与单线程程序相似的执行时间。

在我的#pragma omp 并行部分中,每个线程计算自己的大数组部分并获取该部分的总和。这些都可以并行运行。然后我希望线程按顺序运行,并将每个总和添加到 TotalSum IN ORDER。所以线程 1 必须等待线程 0 完成,依此类推。我在#pragma omp 关键部分中有这部分。一切运行良好,除了只有线程 0 正在完成然后程序退出。如何确保其他线程继续轮询?我试过 sleep() 和 while 循环,但它在线程 0 完成后继续退出。

我没有使用#pragma omp parallel for,因为我需要跟踪每个线程访问的主数组的特定范围。以下是相关代码部分的缩短版本:

//DONE and MasterArray are global arrays. DONE keeps track of all the threads that have completed

int Function()
{
    #pragma omp parallel
    {
    int ID = omp_get_thread_num
    variables: start,end,i,j,temp(array)  (all are initialized here)
    j = 0;

    for (i = start; i < end; i++)
    {
         if(i != start)
               temp[j] = MasterArray[i];
         else
               temp[j] = temp[j-1] + MasterArray[i];
         j++;
    }



    #pragma omp critical
    {     
        while(DONE[ID] == 0 && ERROR == 0) {

           int size = sizeof(temp) / sizeof(temp[0]);           

           if (ID == 0)  {
              Sum = temp[size];
              DONE[ID] = 1;
              if (some situation)
                 ERROR = 1;   //there's an error and we need to exit the function and program
           }
           else if (DONE[ID-1] == 1) {
              Sum = temp[size];
              DONE[ID] = 1;
              if (some situation)
                 ERROR = 1;   //there's an error and we need to exit the function and program
           }
        }
     }
     }
     if (ERROR == 1)
         return(-1);
     else
         return(0);
   }

这个函数在初始化线程数后从main调用。在我看来,并行部分完成了,然后我们检查错误。如果发现错误,则循环终止。我意识到这里出了点问题,但我无法弄清楚它是什么,现在我只是在兜圈子。任何帮助都会很棒。同样,我的问题是该函数仅在线程 0 执行后退出,但没有标记错误。我也让它在 pthreads 中运行,但执行起来更简单。 谢谢!

【问题讨论】:

    标签: c multithreading parallel-processing openmp


    【解决方案1】:

    您尝试使用#pragma omp critical 对线程进行排序是完全错误的。任何时候临界区都可以只有一个线程,线程到达临界区的顺序是不确定的。因此,在您的代码中可能会发生这种情况,例如线程#2 首先进入临界区并且永远不会离开它,等待线程#1 完成,而线程#1 和其余线程在#pragma omp critical 等待。即使有些线程,例如线程#0,很幸运能够以正确的顺序完成临界区,它们将在并行区域末尾的隐式屏障上等待。也就是说,这段代码几乎可以保证死锁。

    我建议你做一些更简单自然的事情来排序你的线程,即有序部分。它应该是这样的:

    #pragma omp parallel
    {
        int ID = omp_get_thread_num();
    
        // Computations done by each thread
    
        #pragma omp for ordered schedule(static,1)
        for( int t=0; t<omp_get_num_threads(); ++t )
        {
            assert( t==ID );
            #pragma omp ordered
            {
                // Do the stuff you want to be in order
            }
        }
    }
    

    因此,您创建了一个并行循环,其迭代次数等于该区域中的线程数。 schedule(static,1) 子句明确指出,迭代按照线程 ID 的顺序为每个线程分配一个; ordered 子句允许在循环内使用有序部分。现在在循环体中放置一个有序部分(#pragma omp ordered 之后的块),它将按照迭代顺序执行,这也是线程 ID 的顺序(由断言确保)。

    更多信息,你可以看看这个问题:How does the omp ordered clause work?

    【讨论】:

    • 感谢您的建议。我已经这样做了,它现在成功地完成了所有线程。我担心每个线程的本地变量。这些变量在进入临界区时是否默认对每个线程保持私有?还是我需要在 for 循环中将它们声明为私有变量?
    • 我不确定,但假设并行区域的本地和私有变量在该区域内的工作共享结构中保持私有(可能除非另有说明)。我试图在 OpenMP 规范中找到相关内容,但没有成功。为了安全起见,将这些变量声明为循环私有可能没有害处。
    猜你喜欢
    • 2014-04-20
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多