9 votes

Std::vector privé préalloué dans une boucle for parallélisée OpenMP en C++.

J'ai l'intention d'utiliser des tampons std::vector<size_t> buffer(100) , un dans chaque thread dans une parallélisation d'une boucle, comme le suggère ce code :

std::vector<size_t> buffer(100);
#pragma omp parallel for private(buffer)
for(size_t j = 0; j < 10000; ++j) {
    // ... code using the buffer ...
}

Ce code ne fonctionne pas. Bien qu'il y ait un tampon pour chaque thread, ceux-ci peuvent avoir une taille de 0.

Comment puis-je allouer le tampon au début de chaque thread ? Puis-je encore utiliser #pragma omp parallel for ? Et puis-je le faire plus élégamment que cela ?

std::vector<size_t> buffer;
#pragma omp parallel for private(buffer)
for(size_t j = 0; j < 10000; ++j) {
    if(buffer.size() != 100) {
        #pragma omp critical
        buffer.resize(100);
    }
    // ... code using the buffer ...
}

13voto

Mysticial Points 180300

Divisez la région OpenMP comme indiqué dans cette question .

Ensuite, déclarez le vecteur à l'intérieur de la région extérieure, mais en dehors de la boucle for elle-même. Cela permettra de créer un vecteur local pour chaque thread.

#pragma omp parallel
{
    std::vector<size_t> buffer(100);

#pragma omp for
    for(size_t j = 0; j < 10000; ++j) {
    {

        // ... code using the buffer ...

    }
}

11voto

curly_pinguin Points 123

La question et la réponse acceptée existent depuis un certain temps, voici quelques informations supplémentaires qui donnent un aperçu supplémentaire d'openMP et qui pourraient donc être utiles à d'autres utilisateurs.

En C++, le private et firstprivate clause traite les objets de classe différemment :

Depuis l'interface de programme d'application OpenMP v3.1 :

privé le nouvel élément de la liste est initialisé, ou a une valeur initiale indéfinie, comme s'il était avait été déclaré localement sans initialisateur. L'ordre dans lequel les constructeurs par défaut pour les différentes variables privées de la classe type sont appelés est non spécifié.

premierprivé pour les variables de type classe, un constructeur de copie est invoqué pour effectuer l'initialisation. initialisation des variables de la liste.

c'est-à-dire private appelle le constructeur par défaut, alors que firstprivate appelle le constructeur de copie de la classe correspondante.

Le constructeur par défaut de std::vector construit un conteneur vide sans éléments, c'est pourquoi les tampons ont une taille de 0.

Pour répondre à la question, il s'agirait d'une autre solution qui ne nécessite pas de diviser la région OpenMP :

std::vector<size_t> buffer(100, 0);  
#pragma omp parallel for firstprivate(buffer)
for (size_t j = 0; j < 10000; ++j) {
  // use the buffer
}

EDIT un mot d'avertissement concernant les variables privées en général : la taille de la pile de threads est limitée et, à moins d'être explicitement définie (variable d'environnement OMP_STACKSIZE ) dépendant du compilateur. Si vous utilisez des variables privées ayant une grande empreinte mémoire, le dépassement de pile peut devenir un problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X