【问题标题】:Dijkstra's algorithm openmp strange behaviorDijkstra 的算法 openmp 的奇怪行为
【发布时间】:2012-11-18 08:46:07
【问题描述】:

我正在尝试运行我在此处下载的 Dijkstra 算法的 openmp 实现 heather.cs.ucdavis.edu/~matloff/OpenMP/Dijkstra.c

如果我从 5 到 6 再添加一个顶点,使从 0 开始的路径经过两个顶点,我的程序无法给出正确的结果,说 0 和 6 之间的距离是无限的 :^( 可能是什么原因?

#define LARGEINT 2<<30-1  // "infinity"
#define NV 6

// global variables, all shared by all threads by default

int ohd[NV][NV],  // 1-hop distances between vertices
mind[NV],  // min distances found so far
notdone[NV], // vertices not checked yet
nth,  // number of threads
chunk,  // number of vertices handled by each thread
md,  // current min over all threads
mv;  // vertex which achieves that min

void init(int ac, char **av)
{  int i,j;
for (i = 0; i < NV; i++)  
  for (j = 0; j < NV; j++)  {
     if (j == i) ohd[i][i] = 0;
     else ohd[i][j] = LARGEINT;
  }
ohd[0][1] = ohd[1][0] = 40;
ohd[0][2] = ohd[2][0] = 15;
ohd[1][2] = ohd[2][1] = 20;
ohd[1][3] = ohd[3][1] = 10;
ohd[1][4] = ohd[4][1] = 25;
ohd[2][3] = ohd[3][2] = 100;
ohd[1][5] = ohd[5][1] = 6;
ohd[4][5] = ohd[5][4] = 8;
for (i = 1; i < NV; i++)  {
  notdone[i] = 1;
  mind[i] = ohd[0][i];
}
}

// finds closest to 0 among notdone, among s through e
void findmymin(int s, int e, int *d, int *v)
{  int i;
  *d = LARGEINT; 
  for (i = s; i <= e; i++)
     if (notdone[i] && mind[i] < *d)  {
        *d = ohd[0][i];
        *v = i;
     }
}

// for each i in [s,e], ask whether a shorter path to i exists, through
// mv
void updateohd(int s, int e)
{  int i;
   for (i = s; i <= e; i++)
      if (mind[mv] + ohd[mv][i] < mind[i])  
     mind[i] = mind[mv] + ohd[mv][i];
}

void dowork()
{  
   #pragma omp parallel  // Note 1  
   {  int startv,endv,  // start, end vertices for this thread
      step,  // whole procedure goes NV steps
      mymd,  // min value found by this thread
      mymv,  // vertex which attains that value
      me = omp_get_thread_num();  // my thread number
      #pragma omp single   // Note 2
      {  nth = omp_get_num_threads();  chunk = NV/nth;  
     printf("there are %d threads\n",nth);  }
      // Note 3
      startv = me * chunk; 
      endv = startv + chunk - 1;
      for (step = 0; step < NV; step++)  {
     // find closest vertex to 0 among notdone; each thread finds
     // closest in its group, then we find overall closest
     #pragma omp single 
     {  md = LARGEINT; mv = 0;  }
     findmymin(startv,endv,&mymd,&mymv);
     // update overall min if mine is smaller
     #pragma omp critical  // Note 4
     {  if (mymd < md)  
          {  md = mymd; mv = mymv;  }
     }
     // mark new vertex as done 
     #pragma omp single 
     {  notdone[mv] = 0;  }
     // now update my section of ohd
     updateohd(startv,endv);
     #pragma omp barrier 
      }
   }
}

int main(int argc, char **argv)
{  int i;
   init(argc,argv);
   dowork();  
   // back to single thread now
   printf("minimum distances:\n");
   for (i = 1; i < NV; i++)
      printf("%d\n",mind[i]);
}

【问题讨论】:

    标签: c++ parallel-processing openmp dijkstra


    【解决方案1】:

    这里有两个问题:

    如果线程数不均分值个数,那么这个分工

      startv = me * chunk;
      endv = startv + chunk - 1;
    

    将保留最后一个 (NV - nth*(NV/nth)) 元素未完成,这意味着距离将保留在 LARGEINT。这可以通过多种方式解决;目前最简单的方法是将所有剩余的工作交给最后一个线程

      if (me == (nth-1)) endv = NV-1;
    

    (这会导致不必要的负载不平衡,但这是让代码正常工作的合理开始。)

    另一个问题是在设置notdone[]之前已经忽略了一个障碍

     #pragma omp barrier
     #pragma omp single 
     {  notdone[mv] = 0;  }
    

    这确保notdone 被更新并且updateohd() 仅在每个人完成他们的findmymin() 并更新mdmv 之后才启动。

    请注意,很容易将错误引入您开始使用的原始代码;使用的全局变量很难推理。 John Burkardt 在他的网站上有一个 nicer version 用于教学的相同算法,该算法几乎得到了过多的评论并且更容易追踪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多