openmp命令关键部分

时间:2014-11-29 05:37:53

标签: c multithreading parallel-processing openmp

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

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

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

//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中运行它,但执行起来更简单。 谢谢!

1 个答案:

答案 0 :(得分:2)

您尝试使用#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?