2

我想知道诸如加法和乘法之类的 SSE/AVX 操作是否可以是原子操作?我问这个的原因是,在 OpenMP 中,原子构造仅适用于有限的一组运算符。它不适用于例如 SSE/AVX 添加。

假设我有一个float4对应于 SSE 寄存器的数据类型,并且为 float4 定义了加法运算符以进行 SSE 加法。在 OpenMP 中,我可以使用以下代码对数组进行归约:

float4 sum4 = 0.0f; //sets all four values to zero
#pragma omp parallel
{
    float4 sum_private = 0.0f;
    #pragma omp for nowait
    for(int i=0; i<N; i+=4) {
        float4 val = float4().load(&array[i]) //load four floats into a SSE register
        sum_private4 += val; //sum_private4 = _mm_addps(val,sum_private4)
    }
    #pragma omp critical
    sum4 += sum_private;
}
float sum = horizontal_sum(sum4); //sum4[0] + sum4[1] + sum4[2] + sum4[3]

但是一般来说,原子比关键要快,我的直觉告诉我 SSE/AVX 操作应该是原子的(即使 OpenMP 不支持它)。这是 OpenMP 的限制吗?我可以使用例如英特尔线程构建块或 pthreads 来将其作为原子操作来执行吗?

编辑:根据 Jim Cownie 的评论,我创建了一个新功能,这是最好的解决方案。我验证它给出了正确的结果。

float sum = 0.0f;
#pragma omp parallel reduction(+:sum)
{
    Vec4f sum4 = 0.0f;  
    #pragma omp for nowait
    for(int i=0; i<N; i+=4) {
        Vec4f val = Vec4f().load(&A[i]); //load four floats into a SSE register
        sum4 += val; //sum4 = _mm_addps(val,sum4)
    }
    sum += horizontal_add(sum4);
}

编辑:基于评论 Jim Cownie 和 Mystical 在此线程 OpenMP atomic _mm_add_pd上的评论,我现在意识到 OpenMP 中的归约实现不一定使用原子运算符,最好依靠 OpenMP 的归约实现而不是尝试使用原子操作。

4

1 回答 1

3

SSE 和 AVX 通常不是原子操作(但多字 CAS 肯定会很好)。

您可以使用 tbb 或 ppl 中的可组合类模板进行更通用的缩减和线程本地初始化,将其视为由线程 id 索引的同步哈希表;它与 OpenMP 一起工作得很好,并且不会自行启动任何额外的线程。

您可以在 tbb 站点和 msdn 上找到示例。

关于评论,请考虑以下代码:

x = x + 5

您应该将其视为以下内容,尤其是在涉及多个线程时:

while( true ){
    oldValue = x
    desiredValue = oldValue + 5
    //this conditional is the atomic compare and swap
    if( x == oldValue )
       x = desiredValue
       break;
}

说得通?

于 2013-05-14T22:55:24.403 回答