C++ OpenMP writing to specific element of a shared array/vector

I have a long-running simulation program and I plan to use OpenMP for paralleling some codes for speedup. I'm new to OpenMP and have the following question.

Given that the simulation is a stochastic one, I have following data structure and I need to capture age-specific count of seeded agents [Edited: some code edited]:

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()

As the variable seed_by_age is shared across threads, I know I have to protect it properly. So in (b), I used #pragma omp flush(seed_by_age[agents[i].ageGroup]) But the compiler complains "error: expected ')' before '[' token"

I'm not doing reduction, and I try to avoid 'critical' directive if possible. So, am I missing something here? How can I properly protect a particular element of the vector?

Many thanks and I appreciate any suggestions.

  • Development box: 2 core CPU, target platform 4-6 cores
  • Platform: Windows 7, 64bits
  • MinGW 4.7.2 64 bits (rubenvb build)

  • You can only use flush with variables, not elements of arrays and definitely not with elements of C++ container classes. The indexing operator for std::vector results in a call to operator[] , an inline function, but still a function.

    Because in your case std::vector::operator[] returns a reference to a simple scalar type, you can use the atomic update construct to protect the updates:

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

    As for not using reduction, each thread touches seed_by_age[0] when the condition inside the loop is met thereby invalidating the same cache line in all other cores. Access to the other vector elements also leads to mutual cache invalidation but assuming that agents are more or less equally distributed among the age groups, it would not be that severe as in the case with the first element in the vector. Therefore I would propose that you do something like:

    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;
    

    #pragma omp flush(seed_by_age[agents[i]].ageGroup)
    

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


    I am afraid, that your #pragma omp flush statement is not sufficient to protect your data and prevent a race condition here. If someRandomCondition() is true in only a very limited number of cases you could use a critical section for the update of your vector without loosing too much speed. Alternatively, if the size of your vector seed_by_age is not too large (which I assume) than it could be efficient to have a private version of the vector for each thread which you merge right before leaving the parallel block.

    链接地址: http://www.djcxy.com/p/79264.html

    上一篇: 如何安全地平行for

    下一篇: C ++ OpenMP写入共享数组/矢量的特定元素