OpenMP中的并行合并排序

时间:2012-12-10 23:30:48

标签: c++ c parallel-processing openmp sections

我在this论文中看到了并行合并排序算法。这是代码:

void mergesort_parallel_omp (int a[], int size, int temp[], int threads) 
{  
    if ( threads == 1)       { mergesort_serial(a, size, temp); }
    else if (threads > 1) 
    {
         #pragma omp parallel sections
         {
          #pragma omp section
             mergesort_parallel_omp(a, size/2, temp, threads/2);
          #pragma omp section
             mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2, threads - threads/2);
         }
merge(a, size, temp); 
    } // threads > 1
}

我在多核上运行它。发生的事情是,在树的叶子上,2个线程并行运行。完成工作后,其他2个线程开始,依此类推。即使我们为所有叶子节点都有免费核心。

我认为原因是这个OpenMP代码不会在并行区域内创建并行区域。我是对的吗?

3 个答案:

答案 0 :(得分:7)

“我认为原因是OpenMP无法在并行区域内创建并行区域”

您可以拥有平行区域的平行区域。

  

OpenMP并行区域可以彼此嵌套。如果嵌套   并行性已禁用,然后是由线程创建的新团队   在并行区域内遇到并行构造   仅遇到线程。如果嵌套并行性已启用,   那么新团队可能包含多个帖子source)。

为了正确运行您的代码,您需要致电omp_set_nested(1)omp_set_num_threads(2)

  

可以通过设置启用或禁用嵌套并行性   OMP_NESTED环境变量或调用omp_set_nested()函数

答案 1 :(得分:2)

这个问题的现代答案是使用任务而不是部分。任务在OpenMP 3.0(2009)中添加,比嵌套并行和部分更好/更容易,因为嵌套并行可能导致超额订阅(比可用的CPU更活跃的线程),这会导致显着的性能下降。对于任务,您有一组与CPU数量相匹配的线程,并且将处理任务。因此,您不需要使用threads参数进行手动处理。一个简单的解决方案如下所示:

// span parallel region outside once outside
void mergesort_omp(...) {
    #pragma omp parallel
    #pragma omp single
    mergesort_parallel_omp(...)
}


void mergesort_parallel_omp (int a[], int size, int temp[]) 
{  
    #pragma omp task
    mergesort_parallel_omp(a, size/2, temp);

    mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);

    #pragma omp taskwait
    merge(a, size, temp); 
}

但是,为太小的工作块创建任务仍然存在问题,因此基于工作粒度来限制并行性是有用的,例如,就这样:

void mergesort_parallel_omp (int a[], int size, int temp[]) 
{  
    if (size < size_threshold) {
        mergesort_serial(a, size, temp);
        return;
    }
    #pragma omp task
    mergesort_parallel_omp(a, size/2, temp);

    mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);

    #pragma omp taskwait
    merge(a, size, temp); 
}

答案 2 :(得分:0)

也许我完全忽略了这一点......但是如果你想在两个以上的线程上执行,你是否意识到你需要设置环境变量OMP_NUM_THREADS?