将此视为评论。您的显式任务区域写错了,此外它也是多余的。您在每次迭代中只生成一个显式任务,然后等待它以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.