C++ OpenMP запис в специфичен елемент от споделен масив/вектор

Имам дългогодишна програма за симулация и планирам да използвам 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-ядрен процесор, целева платформа 4-6 ядра
  • Платформа: Windows 7, 64 бита
  • MinGW 4.7.2 64 бита (изграждане на rubenvb)

person YamHon.CHAN    schedule 28.06.2013    source източник


Отговори (3)


Можете да използвате 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;
person Hristo Iliev    schedule 28.06.2013

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

опитайте се да затворите всичките си скоби, това ще поправи грешката на компилатора.

person alexbuisson    schedule 28.06.2013
comment
ageGroup не е член на seed_by_age (което е вектор) - person YamHon.CHAN; 28.06.2013

Опасявам се, че вашият израз #pragma omp flush не е достатъчен, за да защити вашите данни и да предотврати състояние на състезание тук. Ако someRandomCondition() е вярно само в много ограничен брой случаи, можете да използвате критична секция за актуализиране на вашия вектор, без да губите твърде много скорост. Като алтернатива, ако размерът на вашия вектор seed_by_age не е твърде голям (което предполагам), тогава може да е ефективно да имате частна версия на вектора за всяка нишка, която обединявате точно преди да напуснете паралелния блок.

person pTz    schedule 28.06.2013