当前位置: 首页 > 知识库问答 >
问题:

OpenMP reduction子句对于循环计数的大长int不起作用

彭霄
2023-03-14

下面有一段代码:

#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<=1000000000的情况下都能正常工作,并给出以下输出:

n=1000000000

总数=500000000(0,500000000)=500000000

t=11297毫秒

但如果要使N大10倍,则输出是不正确的(第2行):

n=10000000000

总数=705032704(0,705 032704)=705032704

t=112660毫秒

这里的第二行必须是

总数=500000000(2,500000000)=705032706

我不能理解为什么程序在N=1e10时工作不正确,尽管N是长int。

共有1个答案

亢正德
2023-03-14

检查中存在竞态条件:

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检查本身逐个读取n,尽管这仅仅是不够的。

总体而言,最好使用实际的OpenMP约简或自定义构建的约简,以及支持实际原子操作的足够大的数据类型。

 类似资料:
  • 问题内容: 我有以下简单脚本,在其中运行循环并希望维护。我无法弄清楚为什么计数器没有更新。是由于创建了subshel​​l导致的吗?我该如何解决呢? 问题答案: 首先,您没有增加计数器。更改成或将增加它。 其次,在您推测时将子shell变量反向传播给被调用者比较困难。子shell中的变量在子shell外部不可用。这些是子进程本地的变量。 解决此问题的一种方法是使用临时文件存储中间值:

  • 问题内容: 这个问题已经在这里有了答案 : 从列表中删除项目并对其进行迭代时出现奇怪的结果 (4个答案) 5年前关闭。 对于我的一生,我无法弄清楚为什么我的IF语句没有受到攻击。在很多情况下,n的余数//放在结果列表中的最后一个数字为0。 问题答案: 问题是您要在迭代列表时修改列表,因此所有偶数都将被跳过。因此,条件总是。 该循环跟踪指数的,所以当你在索引中删除的项目在,下一个项目个位置转变为当前

  • 我正在使用NamedParameterJdbcTemboard来运行我的查询。查询如下: 现在,我调用一个web服务,它返回一个ID列表。因此,我使用NamedParameterJdbcTemplate将ID列表映射到“客户ID”。然而,当ID列表达到1000多个时,我遇到了一个问题。我已经了解到,DB将无法处理包含100或1000个以上数据的IN。 由于我只能接收ID列表,您能否建议除了Name

  • 问题内容: 我写了这段代码,它将一个小写的英语短语翻译成猪拉丁。 但是,它对短语中的最后一个单词没有任何作用。 如果我使用“快速的棕色狐狸跳过懒狗”这句话,我会得到“ ethay uickqayownbray oxfay umpedjay overay ethay azylay狗” 这里的一切都正确,除了硬道理!为什么不起作用?如果我使用“ hello world”作为短语,也会发生同样的事情。

  • 我是新的mongodb,我有一个文档在我的db如下: {“_id”:{“$oid”:“546e916cd38e0b3e0e79592f”},名称:“'hamed”,“实体:[“1”,“2”]} 现在我想阅读实体为[“1”,“2”]的aal文档,为此我尝试了以下代码: 但它不返回任何东西...有人能帮助我如何正确地写我的where子句吗?

  • 此方法重复读取命令并执行它们,直到游戏结束。完成的变量为true时,表示玩家/用户点击了退出并想要结束游戏——从而退出循环并执行到方法结束。 但我观察到循环有一种奇怪的行为。它循环得非常好(省略以下行时显示stopWatch.getTime()的连续计数: 但是当我把它们放回去时,它会停止显示秒表的连续递增时间,因为它会朝着时间限制增加(在这一点上,它应该停止)。即使玩家没有输入任何命令或输入。

  • 问题内容: 我希望我的程序一直问这个问题,直到得到可以使用的响应为止,尤其是0到20之间的一个数字。此类中还有很多其他内容,因此这里有一段摘录,其中do- while是(我已经命名了变量以及所有内容。 问题答案: 您在表达式中使用了一个赋值: 您可以替换为 或更好 如果变量和在其他地方未使用,则可以消除它们,从而为您提供:

  • 问题内容: 我试图让用户有机会在引入会产生错误但又无法正常工作的东西之后重复输入,因为一旦发现 错误, 就不会再次执行try东西,而是直接进入catch东西,生成一个永恒的东西。柱。这是我的代码: 问题答案: 输入非整数时,对的调用不会消耗非整数。您需要致电(或)使用它。就像是,