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

Threads & Processus C++ Discussion :

Threading Building Blocks (TBB), section critique et mutex


Sujet :

Threads & Processus C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 31
    Points : 13
    Points
    13
    Par défaut Threading Building Blocks (TBB), section critique et mutex
    Salut, j’ai déjà posté sur le forum au moment où je cherchais à me former sur la progra multithread. J’ai passé en revue sur developpez.net avec tous ceux qui m’ont filé un coup de main (merci encore !) , les frameworks Boost, TBB et OMP. J’ai décidé de retenir TBB comme solution finale pour des questions de facilité d’intégration.

    Au stade du « redesign » mon source, je m’aperçois que je ne suis pas à l’aise avec la notion de « donnée partagée » qui est peut-être à l’origine de mes plantages répétés…. L’idée est la suivante : j’avais au départ la construction d’un objet qui dispose d’une méthode next(), laquelle méthode permet à l’occasion di’térations, de générer une suite de valeur. C’et donc cette boucle que j’ai choisi de paralléliser, connaissant dès le départ mon nombre total d’itérations, au moyen d’un parallel_for

    Ce que j’observe :, des plantages interviennent dans l’exécution de mon parallel_for, je n’arrive jamais à sortir de la boucle placée dans la méthode
    Void operator()
    De ma classe (alors que l’idée c’est de pouvoir récupérer en fin de traitement, toues mes valeurs dans un tableau).

    Ce que j’ai remarqué : c’est que je suis en mesure de tracer l’index de parcours du blocked_range passé en paramètre à la fonction, et que le plantage n’intervient jamais pour le même index.

    Qqs questions «conceptuelles»: dans quel cas je peux être certain que j’ai précisément affaire à des données partagées lors de l’exécution de ma boucle?

    Dans la mesure où mon exécution ne semble jamais être stoppée au même endroit, est-ce que je considère que c’est mes threads qui arrivent n’importe quand/comment sur la ligne de calcul ?

    Comment je mets en place avec TBB une synchronisation des threads pour la zone pour laquelle j’ai un doute (avec Boost j’avais vu que l’on mettait des mutex, avec TBB je trouve rien)?c’est quoi la règle pour placer les points de synchronisation au(x) bon(s) endroit (s) ?

    Merci si vous avez des éléments pour me faire comprendre.

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Salut simong,

    Je ne saisis pas bien ce qui te gêne, la problématique des données partagées dans TBB est la même que dans tout code multi-thread.

    La règle d'or reste :
    Si une donnée est accédé simultanément par plusieurs threads en
    1) Lecture : pas besoin de mutex
    2) Écriture : mutex obligatoire.

    Donc si la fonction next() modifie l'état de la classe, c'est à dire modifie des données internes de la classe alors il faut entourer l'appel à next() par un mutex.
    D'ailleurs TBB fournit une implémentation de mutex portable "tbb::mutex" (en attendant le C++0X qui fournira std::mutex.)

    Par exemple, définissons la classe Data suivante :
    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
     
    #include <iostream>
    #include <tbb/parallel_for.h>
    #include <tbb/mutex.h>
     
    struct Data
    {
       Data():i_(0){}
       void f()
       {
          i_++;
          std::cout << i_ << " ";
          i_--;
       }
       int i_;
    };
    Data est conçu de telle sorte qu'à tout instant i_ ne peut valoir que un, à l'intérieur de f() ou zéro.
    Mais le code suivant :
    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
     
    struct Task
    {
       Data* d_;
       Task(Data* d):d_(d){}
       void operator()(size_t) const
       {
          d_->f();
       }
    };
     
    int main()
    {
       Data d;
       tbb::parallel_for(0, 10, 1, Task(&d));
    }
    affiche :
    1 4 3 4 4 4 4 2 4 4

    Tout le problème vient du fait que le parallel_for utilise la fonction f() qui modifie d (elle écrit dans i_). Ce qu'il se passe probablement passe ici, c'est que TBB détecte mon quad-core, donc il y a quatre threads qui se rue en même temps dans f() en boucle, et vu que std::cout prend infiniment plus de temps que l'incrémentation/décrémentation de i_ les quatres threads se retrouvent ensemble presque tout le temps dans le std::cout avec i_ qui vaut quatre.

    Pour corriger le problème il faut un mutex.
    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
     
    struct TaskMutex
    {
       tbb::mutex* m_;
       Data* d_;
       TaskMutex(Data* d, tbb::mutex* m):d_(d), m_(m){}
       void operator()(size_t) const
       {
          m_->lock();
          d_->f();
          m_->unlock();
       }
    };
     
    int main()
    {
       Data d;
       tbb::mutex m;
       tbb::parallel_for(0, 10, 1, TaskMutex(&d, &m));
       std::cout << std::endl;
    }
    Ce qui affiche bien
    1 1 1 1 1 1 1 1 1 1
    Alors bien sûr, dans ce cas le fait que i_ soit différent de un n'est pas bien grave. Mais si je me servais de i_ comme indice pour accéder à un tableau une valeur de i_ trop grande viendrait jardiner la mémoire ce qui pourrait conduire à un crash.

    Il faut aussi garder à l'esprit que le prix du lock est élevé. Il y a maintenant trois threads sur quatre qui passent leur temps à attendre que le mutex se libère, donc pas la peine d'espérer un quelconque gain de parallélisme dans ce cas.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 31
    Points : 13
    Points
    13
    Par défaut
    Salut Arzar, eh bien merci pour cet explication. Ce qui me gênait c'était à la base la notion de "donnée partagée".... Tu différencies le cas "lecture" du cas "écriture"/"modification de l'état de la classe" cela me permet déjà de mieux positionner le débat. Merci vraiment beaucoup.

    Après j'ai une phrase qui m'interpèle c'est la dernière : "Il faut aussi garder à l'esprit que le prix du lock est élevé. Il y a maintenant trois threads sur quatre qui passent leur temps à attendre que le mutex
    se libère, donc pas la peine d'espérer un quelconque gain de parallélisme dans ce cas": j'imagine que tu mets ici le coût de ta gestion de mutex face au gain escompté de la parallélisation sur le traitement (dans ton cas, simple)? Sinon comment faire quand on a effectivement besoin de mutex???? Merci.

Discussions similaires

  1. F# et les Thread Building Blocks d'Intel
    Par Franck Z dans le forum F#
    Réponses: 2
    Dernier message: 14/03/2011, 01h15
  2. Comment utiliser TBB ? (Intel Thread Building Blocks)
    Par LostInGeekLand dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 20/03/2008, 15h27
  3. Réponses: 11
    Dernier message: 02/08/2007, 15h07
  4. [D7][IPC]Section critique ou Mutex ?
    Par jbat dans le forum Delphi
    Réponses: 5
    Dernier message: 28/06/2007, 21h49

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