0

我之前也问过类似的问题,但由于它的复杂性,我没有得到足够的重视,所以让我重新表述整个问题。

moveT ChooseComputerMove(state)
{
 moveT bestMove;
 maxMove(state,bestMove);

 return bestMove;
}

int maxMove(state, bestMove)
{

  int v = -1000;

  #pragma omp parallel for 
  for(int i = 0; i< nMoves; i++)
  {

   moveT move = validMoves[i];

   makemove(state,move);

   #pragma omp task 

   rating = -maxMove(state, move);

    if(rating < v)
      {v=rating ; bestMove = move;}

    #pragma omp taskwait   

    Retractmove(state,move)
 }

 return v;
}

我的代码在语义上是否正确;我已经在我的代码中对其进行了测试,它给了我分段错误;

更新:抱歉拼写错误,我已经编辑了我的代码。

4

2 回答 2

4

将此视为评论。您的显式任务区域写错了,此外它也是多余的。您在每次迭代中只生成一个显式任务,然后等待它以taskwait. 但由于任务执行可能会延迟,任务本身可能会在比较运算符的行之后执行。例如

#pragma omp task
rating = -maxMove(state, move); // <-- This stmt is the body of the task

if(rating < v)
  {v=rating ; bestMove = move;}

#pragma omp taskwait

task任务的主体是pragma之后的下一个块。

实际的执行流程可能是:

  • 任务已创建但已排队。
  • if(rating < v) ....语句被执行。
  • 在处理完所有任务之前,该taskwait构造会阻塞执行。这将启动任务的执行。
  • 计算了新的评分,但由于语句已经执行,因此值v永远不会更新。if

您宁愿将这两个语句都放在一个task构造中并删除,taskwait因为它隐含在并行区域的末尾。由于makemove修改了state向量,您可能希望使用单任务生产者模式:

#pragma omp parallel
{
   #pragma omp single nowait
   for(int i = 0; i < nMoves; i++)
   {
      moveT move = validMoves[i], opponentsBestMove;

      makemove(state, move);

      #pragma omp task firstprivate(state)
      {
         // Declare rating here
         int rating = -maxMove(state, opponentsBestMove);

         #pragma omp critical
         if (rating > v) { v = rating; bestMove = move; }
      }

      Retractmove(state, move)
   }

   // An implicit taskwait here
}

任务生产者循环仅在一个线程中串行运行(因为该single指令)。然后在并行区域的末尾有一个隐式任务调度点,因此其他线程开始执行排队的任务。默认情况下state是共享的,必须这样做firstprivate才能让任务继承私有版本,否则所有任务会同时修改同一个全局state变量,这会导致问题。私有化state会导致更高的内存使用率,因此允许将任务分配到递归树的底部并不是一个好主意。相反,您应该在某个级别停止生成任务并继续串行执行。这也将减少显式任务引起的开销。

Another thing to notice - unless special measures are taken, only the top-level call would run in parallel. All other recursive calls would result in nested parallel regions and nested parallelism is disabled by default, which means that deeper recursion levels would automatically execute serially. To enable nested parallelism, either set the environment value OMP_NESTED to true or put the following call somewhere in the beginning of the program:

#include <omp.h>

...
omp_set_nested(1);
...
// Now call the recursive function
...

Beware that this might result in a huge number of concurrent threads.

于 2012-12-29T16:32:28.397 回答
0

您在这里尝试实现的是进行并行递归调用。这会给你带来很多问题。

假设您有 8 个物理线程。由于nMoves您的情况不超过 8,因此MaxMove在 8 个并行线程中运行具有不同参数的函数会非常好。但是,在每个调用中,您都试图创建另一个nMoves-1线程,因此您创建的并行线程的复杂性是指数级的。由于物理线程的数量是有限的,因此并行运行每个函数调用不会获得额外的性能,因此最终所有线程都会很忙。此外,与您在函数调用中执行的计算量相比,创建每个线程的开销成本可能太高。

我将删除内部#pragma omp task#pragma omp taskwait注释,并将此代码序列留在已创建的线程中。

您的代码为我运行,我没有遇到分段错误,但我认为这是由您的并行化方法引起的。

于 2012-12-29T12:13:07.103 回答