2

我有一个长时间运行的模拟程序,我计划使用 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])了但编译器在'['令牌之前抱怨“错误:预期')'

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

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

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

3 回答 3

2

您只能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;
于 2013-06-28T09:44:37.843 回答
1
#pragma omp flush(seed_by_age[agents[i]].ageGroup)

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

于 2013-06-28T07:14:59.693 回答
0

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

于 2013-06-28T09:29:28.800 回答