C++ OpenMP reduction子句不适用于大的long int for循环计数
下面是一段代码:C++ OpenMP reduction子句不适用于大的long int for循环计数,c++,openmp,atomic,C++,Openmp,Atomic,下面是一段代码: #include <iostream> #include <fstream> #include <limits> #include <chrono> #include <omp.h> const long int N=1000000000L; class Counter { public: Counter():n(0),N(0){} void operator()() { if(n==INT_M
#include <iostream>
#include <fstream>
#include <limits>
#include <chrono>
#include <omp.h>
const long int N=1000000000L;
class Counter {
public:
Counter():n(0),N(0){}
void operator()()
{
if(n==INT_MAX)
{
#pragma omp atomic update
++N;
#pragma omp atomic write
n=1;
}
else
{
#pragma omp atomic update
++n;
}
}
long int GetTotalCount()
{
return (static_cast<long int>(n)+static_cast<long int>(N)*static_cast<long int>(INT_MAX));
}
friend std::ostream & operator<<(std::ostream & o, Counter & counter)
{
o<<counter.GetTotalCount()<<" ("<<counter.N<<","<<counter.n<<") = "
<<static_cast<long int>(counter.N)*static_cast<long int>(counter.INT_MAX)+static_cast<long int>
(counter.n)
<<std::endl;
return o;
}
private:
const int INT_MAX=std::numeric_limits<int>::max();
int n;
int N;
};
int main(int argc, char **argv)
{
const auto begin = std::chrono::steady_clock::now();
Counter counter;
#pragma omp parallel for simd
for(long int i=0; i<N; ++i)
{
if(i%2==0) counter();
}
const auto end = std::chrono::steady_clock::now();
std::cout<<"N="<<N<<std::endl;
std::cout<<"Total count="<<counter;
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end-begin).count();
std::cout<<"t="<<time<<" ms"<<std::endl;
return 0;
}
#包括
#包括
#包括
#包括
#包括
常量长整数N=100000000升;
班级计数器{
公众:
计数器():n(0),n(0){
void运算符()()
{
如果(n==INT_MAX)
{
#pragma omp原子更新
++N;
#pragma omp原子写入
n=1;
}
其他的
{
#pragma omp原子更新
++n;
}
}
long int GetTotalCount()
{
返回(静态施法(n)+静态施法(n)*静态施法(INT_MAX));
}
friend std::ostream&operator检查中有一个竞争条件:
if(n==INT_MAX)
{
// Nothing prevents another thread to read n here and enter the same branch
#pragma omp atomic update
++N;
#pragma omp atomic write
n=1;
}
因此,两个线程可能同时决定重置n
和增加n
除此之外,您还必须对if检查本身进行原子化读取,尽管仅此还不够
总的来说,您最好使用实际的OpenMP缩减或自定义构建的缩减,以及支持实际原子操作的足够大的数据类型。检查中有竞争条件:
if(n==INT_MAX)
{
// Nothing prevents another thread to read n here and enter the same branch
#pragma omp atomic update
++N;
#pragma omp atomic write
n=1;
}
因此,两个线程可能同时决定重置n
和增加n
除此之外,您还必须对if检查本身进行原子化读取,尽管仅此还不够
总的来说,最好使用实际的OpenMP缩减或自定义构建的缩减,以及支持实际原子操作的足够大的数据类型。如果要添加int n;#pragma omp atomic read x=n;如果(n==int_MAX){…},它没有帮助。如果存在竞态条件,为什么代码在N=10^9 ans更小的情况下正常工作?是的,如回答中所述,仅原子地读取检查是不够的。竞态条件从来都不需要实际导致可检测问题。竞态条件在随机条件下表现为问题是很常见的或者完全模糊的条件。但是,在你的情况下,这很简单:只要n
没有线程会首先进入有问题的if分支。哦,当然。但是我该怎么做才能让代码正常工作呢?你写过我可以使用实际的OpenMP缩减。你的意思是摆脱#pragma omp原子更新和#pragma omp原子写入吗e和使用simd行的#pragma omp parallel中的reduce(+:N,N)子句?是的,您可以对足够大的N
类型使用reduce(+:N)
,或者声明自定义reduce。对于后者,我认为您可以通过实现兼容的“大数”来使用+
类,该类支持从int和自身上的运算符+
进行初始化。如果这不起作用,请使用声明约简
。如果要添加int n;#pragma omp atomic read x=n;如果(n==int\u MAX){…},它没有帮助。如果存在竞态条件,为什么代码在N=10^9 ans更小的情况下正常工作?是的,如回答中所述,仅原子地读取检查是不够的。竞态条件从来都不需要实际导致可检测问题。竞态条件在随机条件下表现为问题是很常见的或者完全模糊的条件。但是,在你的情况下,这很简单:只要n
没有线程会首先进入有问题的if分支。哦,当然。但是我该怎么做才能让代码正常工作呢?你写过我可以使用实际的OpenMP缩减。你的意思是摆脱#pragma omp原子更新和#pragma omp原子写入吗e和使用simd行的#pragma omp parallel中的reduce(+:N,N)子句?是的,您可以对足够大的N
类型使用reduce(+:N)
,或者声明自定义reduce。对于后者,我认为您可以通过实现兼容的“大数”来使用+
类,该类支持从int和自身上的运算符+
初始化。如果这不起作用,请使用声明缩减
。您的问题标题提到“OpenMP缩减子句”。但是,显示的代码中没有。您的问题标题提到“OpenMP缩减子句”。但是,显示的代码中没有。