omp parallel for:如何让线程写入私有数组并在所有线程完成处理后合并所有数组

Posted

技术标签:

【中文标题】omp parallel for:如何让线程写入私有数组并在所有线程完成处理后合并所有数组【英文标题】:omp parallel for : How to make threads write to private arrays and merge all the arrays once all the threads finished processing 【发布时间】:2016-10-27 15:57:38 【问题描述】:

我需要计算z 的值,将它们推入数组Bs2

我尝试使用omp parallel for 并行化处理。

我看到的一个问题是,如果我不将 B[i][j] += zs2[i] += z 语句放在 critical 部分中,我会看到很多 NaN 值正在生成。

只是想知道是否有办法将z 值写入单独的数组(每个线程一个数组)并在最后合并它们。

非常感谢任何帮助。

#pragma omp parallel

    double z;
    #pragma omp parallel for
    for(int t=1; t<n; t++) 
        double phi_i[N];
        double obs_j_seq_t[N];

        for(int i=0; i<N; i++) 
            for(int j=0; j<N; j++) 
                z=phi_i[i]*trans[i*N + j]*obs_j_seq_t[j]*beta[t*N+j]/c[t]; 
                #pragma omp critical
                 
                    B[i][j] += z;
                    s2[i] += z;
                
            
        
    

【问题讨论】:

如果可以使用std::async,为什么还要使用预处理器? 您是否尝试过为每个z 积累使用omp atomic?这比使用临界区要好得多,特别是在没有冲突的情况下(线程访问不同的位置)。另一方面,您是否试图在所有线程中划分嵌套的 for 循环迭代?目前,每个线程都在并行执行所有迭代。你可以考虑在那里使用#pragma omp for collapse(2) 【参考方案1】:

您的代码暴露了一些问题,每个问题都是其性能和/或有效性的潜在杀手:

首先使用#pragma omp parallel,然后添加#pragma omp parallel for。这意味着您正在尝试生成嵌套并行性(另一个并行区域中的并行区域)。首先,这是一个坏主意,其次,默认情况下禁用。因此,您的第二个 parallel 指令将被忽略,并且循环上的工作永远不会被分发,而是由您使用初始 parallel 指令生成的所有线程完全执行。因此,所有线程一次将结果写入Bs2 时存在竞争条件。您通过添加 critical 部分来解决问题,但从根本上说,代码是错误的。 即使您没有这个初始的parallel 指令或启用嵌套并行,您的代码也会由于以下原因出错: 您的z 变量在第二个parallel 区域的线程中是shared,并且由于所有这些线程都对其进行了修改,因此一旦在该区域中产生了多个线程,它的值就未定义。 更根本的是,您尝试在t 上并行化循环,但解决方案在i 上编制索引。这意味着所有线程将竞争更新相同的索引,再次导致竞争条件和无效结果。你可以再次使用critical 指令来解决这个问题,但这只会让代码变得超级慢。您最好在 i 上并行化循环(同时可能在 ti 上交换循环以将后者放在最外层)。

您的代码可能会变成这样(未经测试):

#pragma omp parallel for
for(int i=0; i<N; i++) 
    for(int t=1; t<n; t++) 
        double phi_i[N];       // I guess these need some initialization
        double obs_j_seq_t[N]; // Idem
        for(int j=0; j<N; j++) 
            double z=phi_i[i]*trans[i*N + j]*obs_j_seq_t[j]*beta[t*N+j]/c[t]; 
            B[i][j] += z;
            s2[i] += z;
        
    

【讨论】:

以上是关于omp parallel for:如何让线程写入私有数组并在所有线程完成处理后合并所有数组的主要内容,如果未能解决你的问题,请参考以下文章

通过分离#omp parallel 和#omp for 来减少 OpenMP fork/join 开销

“pragma omp parallel for”中的“omp_get_num_threads”给了我编译错误

OMP SECTIONS 和 DO 在同一个 PARALLEL 块中

OpenMP:不能同时使用 omp parallel for 和 omp task 吗? /错误:工作共享区域可能没有紧密嵌套在工作共享内

在另一个并行循环中调用函数时,函数中的“pragma omp parallel for”无效

嵌套循环中未正确忽略内部循环的 Pragma omp parallel