我想知道加法和乘法等SSE / AVX操作是否可以是原子操作?我之所以这么说是因为在OpenMP中,原子结构只能在一组有限的运算符上运行。它不适用于例如SSE / AVX添加。
假设我有一个与SSE寄存器对应的数据类型float4
,并且为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的简化实现,而不是尝试用原子操作。
答案 0 :(得分:3)
SSE&amp; 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;
}
有意义吗?