如何在OpenMP中使用缩减向量变量?

时间:2015-09-18 06:32:56

标签: c openmp scalar reduction

我想在reduction中使用openmp指令,但它不起作用。编译错误说:

  

"还原:OpenMP'并行用于'指令中的空因子"   (Visual Studio 2015社区)

  

"减少:^需要标量变量"

这是我的代码(字节为unsigned char

void RotXOR (const Byte *s, int n, Byte *t)
{
    int i = 0, q;
    q = n / 8; n %= 8;

    #pragma omp parallel for private(i) reduction()
    for (i = 0; i < 16; i++) {
        t[(q + i) % 16] ^= (s[i] >> n);

        if (n != 0) {
            t[(q + i + 1) % 16] ^= (s[i] << (8 - n));
        }
    }
}

1 个答案:

答案 0 :(得分:1)

从OpenMP 4.0标准p171 for C / C ++:

  

数组可能不会出现在减少条款中。

所以这样做的唯一方法就是创建一个本地的每线程&#34; tt&#34;数组初始化为0,在其上计算并在退出并行部分时以t原子方式更新tt

但无论如何,由于你的环路跳数仅为16,因此并行化开销将远远大于任何潜在的增益,因此从我的观点来看,这只是一个死胡同。

编辑:这就是我的想法:

void RotXOR( const Byte *s, int n, Byte *t ) {
    int q = n / 8;
    n %= 8;

    #pragma omp parallel
    {
        int tt[] = { 0, 0, 0, 0,
                     0, 0, 0, 0,
                     0, 0, 0, 0,
                     0, 0, 0, 0 };
        #pragma omp for
        for ( int i = 0; i < 16; i++ ) {
            tt[( q + i ) % 16] ^= ( s[i] >> n );
            if ( n != 0 ) {
                tt[( q + i + 1 ) % 16] ^= ( s[i] << ( 8 - n ) );
            }
        }
        #pragma omp critical
        for ( int i = 0; i < 16; i++ ) {
            t[i] ^= tt[i];
        }
    }
}

而且我说我不希望性能提升很多(如果有的话),因为行程计数非常小,可以在线程之间分配不多的工作来隐藏线程管理的开销,以及顺序的最终减少

在编写这个解决方案时,我想到了另一个解决方案,但我不知道这两个中哪一个会表现最好...我怀疑第二个版本会比第一个版本更糟糕t的开销和错误分享,但我不确定......

void RotXOR( const Byte *s, int n, Byte *t ) {
    int q = n / 8;
    n %= 8;

    #pragma omp parallel for
    {
        for ( int i = 0; i < 16; i++ ) {
            int idx = ( q + i ) % 16;
            int val = s[i] >> n;
            #pragma omp atomic
            t[idx] ^= val;
            if ( n != 0 ) {
                idx = ( q + i + 1 ) % 16;
                val = s[i] << ( 8 - n );
                #pragma omp atomic
                t[idx] ^= val;
            }
        }
    }
}

最后,由于n的值在进入时是已知的,我想从循环中删除if语句是个好主意,即使它意味着要编写更多的代码。