1

我有这个parallel for循环

struct p
{
    int n;
    double *l;
}

#pragma omp parallel for default(none) private(i) shared(p)
for (i = 0; i < p.n; ++i)
{
    DoSomething(p, i);
}

现在,由于向 中添加了新元素DoSomething(),可能p.n会增加inside p.l。我想以并行方式处理这些元素。OpenMP 手册指出parallel for不能与列表一起使用,因此DoSomething()将这些p.l新元素添加到另一个列表中,该列表按顺序处理,然后与p.l. 我不喜欢这种解决方法。有人知道更清洁的方法吗?

4

1 回答 1

3

OpenMP 3.0 中添加了一个支持动态执行的构造,它就是task构造。任务被添加到队列中,然后尽可能并发地执行。示例代码如下所示:

#pragma omp parallel private(i)
{
    #pragma omp single
    for (i = 0; i < p.n; ++i)
    {
       #pragma omp task
       DoSomething(p, i);
    }
}

这将产生一个新的并行区域。其中一个线程将执行for循环并为每个i. 每个不同的DoSomething()调用都将转换为一个任务,稍后将在空闲线程中执行。但是有一个问题:如果其中一个任务向 中添加了新值p.l,则可能在创建者线程已经退出for循环之后发生。这可以使用任务同步结构和像这样的外部循环来解决:

#pragma omp single
{
   i = 0;
   while (i < p.n)
   {
      for (; i < p.n; ++i)
      {
         #pragma omp task
         DoSomething(p, i);
      }
      #pragma omp taskwait
      #pragma omp flush
   }
}

taskwait构造使线程等待,直到所有排队的任务都被执行。如果将新元素添加到列表中,则条件while将再次变为真,并且将发生新一轮的任务创建。该flush构造应该在线程之间同步内存视图,例如使用共享存储中的值更新优化的寄存器变量。

所有现代 C 编译器都支持 OpenMP 3.0,除了 MSVC,它停留在 OpenMP 2.0 上。

于 2012-08-13T08:09:19.380 回答