【问题标题】:C++ OpenMP writing to specific element of a shared array/vectorC++ OpenMP 写入共享数组/向量的特定元素
【发布时间】:2013-06-28 07:05:21
【问题描述】:

我有一个长时间运行的模拟程序,我计划使用 OpenMP 来并行一些代码以提高速度。我是 OpenMP 新手,有以下问题。

鉴于模拟是随机的,我有以下数据结构,我需要捕获特定年龄的种子代理计数[已编辑:一些代码已编辑]:

class CAgent {
    int ageGroup;
    bool isSeed;
    /* some other stuff */
};

class Simulator {
    std::vector<int> seed_by_age;
    std::vector<CAgent> agents;
    void initEnv();
    /* some other stuff */
};

void Simulator::initEnv() {
     std::fill(seed_by_age.begin(), seed_by_age.end(), 0);

     #pragma omp parallel
     {
          #pragma omp for
          for (size_t i = 0; i < agents.size(); i++)
          {
               agents[i].setup(); // (a)
               if (someRandomCondition())
               {
                   agents[i].isSeed = true;
                   /* (b) */
                   seed_by_age[0]++; // index = 0 -> overall
                   seed_by_age[ agents[i].ageGroup - 1 ]++;
               }
          }
     } // end #parallel
} // end Simulator::initEnv()

由于变量seed_by_age 是跨线程共享的,我知道我必须妥善保护它。所以在 (b) 中,我使用了#pragma omp flush(seed_by_age[agents[i].ageGroup]) 但编译器在 '[' token" 之前抱怨 "error: expected ')'

我没有做减少,如果可能的话,我会尽量避免“关键”指令。那么,我在这里错过了什么吗?如何正确保护向量的特定元素?

非常感谢,我感谢任何建议。

  • 开发箱:2核CPU,目标平台4-6核
  • 平台:Windows 7,64 位
  • MinGW 4.7.2 64 位(rubenvb 构建)

【问题讨论】:

    标签: c++ stl openmp stdvector


    【解决方案1】:

    您只能将flush 用于变量,而不是数组元素,绝对不能用于 C++ 容器类的元素。 std::vector 的索引运算符导致对 operator[] 的调用,这是一个内联函数,但仍然是一个函数。

    因为在您的情况下 std::vector::operator[] 返回对简单标量类型的引用,您可以使用 atomic update 构造来保护更新:

    #pragma omp atomic update
    seed_by_age[0]++; // index = 0 -> overall
    #pragma omp atomic update
    seed_by_age[ agents[i].ageGroup - 1 ]++;
    

    至于不使用归约,当循环内的条件满足时,每个线程都会触及seed_by_age[0],从而使所有其他内核中的同一缓存行无效。访问其他向量元素也会导致相互缓存失效,但假设代理在年龄组中或多或少地平均分布,它不会像向量中的第一个元素那样严重。因此,我建议您执行以下操作:

    int total_seed_by_age = 0;
    
    #pragma omp parallel for schedule(static) reduction(+:total_seed_by_age)
    for (size_t i = 0; i < agents.size(); i++)
    {
        agents[i].setup(); // (a)
        if (someRandomCondition())
        {
            agents[i].isSeed = true;
            /* (b) */
            total_seed_by_age++;
            #pragma omp atomic update
            seed_by_age[ agents[i].ageGroup - 1 ]++;
        }
    }
    
    seed_by_age[0] = total_seed_by_age;
    

    【讨论】:

      【解决方案2】:
      #pragma omp flush(seed_by_age[agents[i]].ageGroup)
      

      尝试关闭所有括号,它将修复编译器错误。

      【讨论】:

      • ageGroup 不是 seed_by_age 的成员(它是一个向量)
      【解决方案3】:

      恐怕您的#pragma omp flush 语句不足以保护您的数据并防止此处出现竞争条件。 如果 someRandomCondition() 仅在非常有限的情况下为真,您可以使用临界区来更新向量,而不会失去太多速度。或者,如果您的向量 seed_by_age 的大小不是太大(我假设),那么在离开并行块之前为您合并的每个线程拥有一个私有版本的向量可能是有效的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多