首页 > 解决方案 > OpenMP 任务和 while 循环

问题描述

我很难理解以下代码中发生的事情:

/*runs with 4 threads*/
int count_good(item_t* item){
    int n=0;
    int pn[num_thr]; 
    #pragma omp parallel
    {
       pn[omp_get_thread_num()]=0;
       #pragma omp single nowait
       {
       while(item){
           #pragma omp task firstprivate(item)
           {
               if(is_good(item))pn[omp_get_thread_num( )]++;           
           }
       item = item ->next;
       }
     }
    #pragma omp atomic
    n+=pn[omp_get_thread_num()];
    }
    return n;
  }

首先打开一个并行区域,一个线程进入 while 循环。每次循环再次开始时,这个线程都会挂起一个任务。线程将任务推送到任务队列。其他线程可以从队列中获取任务并执行它。它是否正确?还是我理解错了?

标签: ctaskopenmp

解决方案


您对任务如何工作以及此代码试图做什么的模型是正确的。单个线程正在创建任务(然后,当它完成时也会执行它们),而其他线程只是在执行它们。

该代码通过计算每个线程看到的“好”项目的数量来执行总和减少。(在 OpenMP 5.0 中,它可以使用任务缩减)。

尽管我之前说过(对此我深表歉意),但这段代码是正确的,因为在单个语句的末尾有一个隐含的障碍。因此,除了执行单个语句的线程之外的所有线程都在那里等待,并拾取并执行任务。一旦执行单个语句的线程耗尽了列表(并生成了所有任务),它也会到达屏障并开始执行任务。一旦所有任务都执行完毕,屏障就可以完成。此时线程将继续(原子地)将它们的贡献添加到全局总和中。

我忘记的是与单个语句相关的隐含障碍(这有点令人困惑,因为看起来类似的主语句没有一个!)。但是,由于有一个,因此此代码很好。(除了每个线程的累加器会受到很多错误共享的性能问题。为了避免每个都应该填充到缓存行的大小[x86 上的 64 字节])。


推荐阅读