IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

itérateur et multi-thread


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut itérateur et multi-thread
    Bonjour,

    J'ai une fonction qui traite les éléments d'une collection en itérant dessus par extraction de ses éléments un par un.
    Voici un exemple de code simplifié:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    struct MyData
    {
    };
     
    class MyRunner
    {
    	std::vector<MyData> f_md_vect;
    public:
    	void init()
    	{
    		// fill f_md_vect with data
    	}
    	void run();
    };
     
    void MyRunner::run()
    {
    	for(auto & md : f_md_vect)
    	{
    		//... traitement d'un élément de la collection ici
    	}
    }
     
    void mainST()
    {
    	MyRunner mr;
    	mr.init();
    	mr.run();
    }
    J'aimerais améliorer les performances de ce code sachant que le traitement de chacun des éléments de la collection est indépendant. Sur base du code qui précède il me suffirait d'appeler la méthode void MyRunner::run() dans autant de threads que voulu.
    Le problème est alors de s'assurer que chaque élément de la collection ne soit traité qu'une seule fois, donc de verrouiller d'une manière ou d'une autre l'itération qui a lieu dans le code for(auto & md : f_md_vect). En d'autres termes, il faudrait extraire l'itérateur de la boucle for et en faire une variable partagée entre les threads.
    Voici une solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    struct MyData
    {
    };
     
    class MyRunnerMT
    {
    	std::vector<MyData> f_md_vect;
    	std::vector<MyData>::iterator f_md_vect_it{}; // null iterator ... (?)
    	std::shared_mutex shmtx;
     
    	MyData *next()
    	{
    		std::lock_guard<std::shared_mutex> lock{shmtx};
    		if (f_md_vect_it == f_md_vect.cend())
    			f_md_vect_it = std::vector<MyData>::iterator{}; // null iterator ... (?)
    		if (f_md_vect_it == std::vector<MyData>::iterator{})
    			return nullptr;
    		return &*f_md_vect_it++;
    	}
    public:
    	void init()
    	{
    		// fill f_md_vect with data
    		if (f_md_vect.size())
    			f_md_vect_it = f_md_vect.begin();
    	}
    	void run();
    };
     
    void MyRunnerMT::run()
    {
    	for (MyData *mdptr; (mdptr = next()) != nullptr;)
    	{
    		MyData & md = *mdptr;
    		//... traitement d'un élément de la collection ici
    	}
    }
     
    void mainMT()
    {
    	MyRunnerMT mr;
    	mr.init();
    	std::future<void> f1 = std::async(&MyRunnerMT::run, &mr);
    	std::future<void> f2 = std::async(&MyRunnerMT::run, &mr);
    	std::future<void> f3 = std::async(&MyRunnerMT::run, &mr);
    	std::future<void> f4 = std::async(&MyRunnerMT::run, &mr);
    	f1.wait();
    	f2.wait();
    	f3.wait();
    	f4.wait();
    }
    Cette solution fonctionne et je l'ai implémentée.
    Mais je me demandais s'il n'y avait pas plus simple et plus lisible.
    Citons ce qui me déplaît:
    -exposer aussi clairement un pointeur (retour de méthode next());
    -initialiser un itérateur avec la valeur "nulle" et en faire la valeur de fin d'itération;
    -le déréférencement de l'itérateur pour en extraire le pointer sous-jacent (&*);
    -utiliser un mutex alors que l'itérateur pourrait être atomic (mais je ne vois pas comment faire).

    Merci pour vos idées

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Ne serais tu pas dans le cadre idéal pour utiliser std::for_each, dans sa version "multi threaded" ?

    Cela pourrait ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void MyRunner::run(){
    std::for_each(std::execution::par, f_md_vect.begin(), f_md_vect.end(),[&](MyData /* const */ & d){
        /* manipulation de chaque élément*/;
    });
    }
    (C++17 inside !!! )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    Ou lancer plusieurs threads en leur donnant chacun un morceau de la collection à traiter. Sous forme de pointeur où commencer et d'un nombre d'objet à traiter.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Salut
    Je n'ai peut-être pas bien compris mais pourquoi ne pas tout simplement utiliser OpenMP pour traiter ta collection en parallèle ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void MyRunner::run(){
        #pragma omp parallel for
        for (unsigned i=0; i<md_vect.size(); i++) {
            /* manipulation de chaque élément*/;
        }
    }

  5. #5
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    C'est ce que fait std::for_each avec std::execution::par (au moins pour libstdc++).

  6. #6
    Invité
    Invité(e)
    Par défaut
    Merci pour l'info, je ne connaissais pas cette fonctionnalité.
    Honnêtement, je ne sais pas si je l'utiliserai un jour car openmp est dispo sur pratiquement tous les compilo de moins de 10 ans et permet, si besoin, de gérer finement la parallélisation.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  2. Réponses: 2
    Dernier message: 15/05/2004, 18h33
  3. Réponses: 16
    Dernier message: 30/01/2004, 11h05
  4. [VB6][active x] faire du multi-thread avec vb
    Par pecheur dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 20/05/2003, 12h01
  5. [Kylix] exception qtinft.dll et multi-threading
    Par leclaudio25 dans le forum EDI
    Réponses: 3
    Dernier message: 27/03/2003, 18h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo