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

SL & STL C++ Discussion :

STL et Multithreading


Sujet :

SL & STL C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 6
    Par défaut STL et Multithreading
    Bonjour à tous.

    J'ai dernièrement voulu multithreader une application faisant un usage intensif de conteneurs de la STL.

    Malheureusement, la version multithreadée est plus lente que l'originale, la faute fort vraisemblablement au fait que deux threads se gênent mutuellement lorsqu'ils allouent de la mémoire pour créer un nouvel élément d'un conteneur.
    (si je ne fais que des accès en lecture à mes conteneurs l'application est bien accélérée par le multithreading).

    (ce problème s'est posé aussi bien sous Windows avec VisualC que sous Linux avec GCC et Stdlibc++)

    Ce problème est censé être résolu :
    • soit par l'utilisation de l'allocator nommé mt_allocator dans la Stdlib de GNU (1) mais ce truc n'est pas portable (et peut être même abandonné)
    • soit par l'utilisation d'une lib telle que Hoard (2), mais que je n'ai pas réussi à faire fonctionner
    • soit peut être (j'ai pas essayé) en créant plusieurs processus plutôt que plusieurs threads, mais ce n'est pas pratique pour leur faire partager des données


    Aussi je viens demander si quelqu'un a déjà eu le même soucis et trouvé une solution, ou s'il faut songer à utiliser autrechose que STL.


    Merci

    (1)http://www-eleves-isia.cma.fr/Doc/li...allocator.html
    (2)http://www.hoard.org/

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Si tu peut choisir ta lib.
    Regard la partie thread de Qt peut être.
    Surtout avec les nouveauté du futur qt 4.4
    http://qt.developpez.com/doc/latest/threads.html

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Une solution c'est d'utiliser des allocateurs sans synchronisation spécifiques à chaque thread.
    Par contre, tu devras libérer la mémoire dans le même thread que celui que t'auras alloué.

  4. #4
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035

  5. #5
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    A mon avis, la solution passe d'abord par une réflexion sur la manière dont est distribué le travail entre les différent threads, de façon à minimiser les besoins de locks.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 6
    Par défaut
    Merci pour ces réponses.

    Je viens de tester la bibliothèque Intel Thread Building Blocks qui semble répondre à mes attentes via l'allocateur "scalable_allocator" qui comme son nom l'indique permet à plusieurs threads d'allouer de la mémoire sans se tapper dessus.
    Je marque donc ce fil résolu.

    J'espère maintenant trouver un équivalent utilisable avec XLC pour pouvoir compiler sur un quadri-PowerPC.

    Pour ceux que ca intéresse, je met en fin de post le code que j'ai utilisé pour mettre en évidence une différence entre l'utilisation ou non de ce fameux allocateur.

    @Mongaulois: merci pour TBB, j'avais oublié de commencer par regarder ICC et ses libs, ce qui est logique quand on utilise un proc Intel

    @JolyLoic: dans mon programme, les deux threads qui tournent travaillent sur des données complètement séparées (donc pas besoin d'exclusion mutuelle), et ne partagent que le système d'allocation mémoire. Donc à mon avis point de salut en dehors de l'utilisation de ce genre de lib.






    Code de deux threads additionnant deux std::vectors avec des clears et des push_back à tire-larigot:

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
     
    #ifdef NULIX
    	#include <pthread.h>
    	#include <iostream>
     
    	#ifdef USE_TBB
    		#include <tbb/scalable_allocator.h>
    		#include <tbb/cache_aligned_allocator.h>
    	#endif
    #endif
     
    #include <stdio.h>
    #include <time.h>
    #include <set>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    #include <time.h>
     
    #ifdef MULTITHREAD
    	#define NBCPU 2
    #else
    	#define NBCPU 1
    #endif
     
    #define T 1000000
    #define N 200
     
    using namespace std;
     
    #ifdef USE_TBB
    	typedef std::vector< long int , tbb::scalable_allocator<long int> > myvector;
    #else
    	typedef std::vector< long int > myvector;
    #endif
     
     
    int test1=0,test2=0;
    myvector a1,b1,c;
    myvector a2,b2,d;
     
    //------------------------------------------------------------------------------------------------------------------------
     
    void* thread1(void*)
    {
    	long int cptT,cptI , i;
    	cout<<"Thread1!\n";
     
    	for (cptT=0;cptT<T;cptT++)
    	{
    		c.clear();
    		myvector::iterator it1,it2;		
    		for(it1=a1.begin(),it2=b1.begin();it1!=a1.end(),it2!=b1.end();it1++,it2++)
    			c.push_back((*it1)+(*it2));
    	}
     
    	cout<<"Verification de C: \n";
    	for (myvector::iterator it=c.begin();it!=c.end();it++) if (*it!=0) test1=11;
     
     
    	cout<<"Fin thread 1.\n";
    	return NULL;
    }
     
    //------------------------------------------------------------------------------------------------------------------------
     
    void* thread2(void*)
    {
    	long int cptT,cptI , i;
    	cout<<"Thread2!\n";
     
    	for (cptT=0;cptT<T;cptT++)
    	{
    		d.clear();
    		myvector::iterator it1,it2;		
    		for(it1=a2.begin(),it2=b2.begin(); it1!=a2.end(),it2!=b2.end(); it1++,it2++)
    			d.push_back((*it1)+(*it2));
    	}
     
    	cout<<"Verification de D: \n";
    	for (myvector::iterator it=d.begin();it!=d.end();it++) if (*it!=0) test2=22;
     
    	cout<<"Fin thread 2.\n";
    	return NULL;
    }
     
    //------------------------------------------------------------------------------------------------------------------------
     
     
    int main( )
    {
        clock_t debut,fin;
        long int i;
     
    	for (i=0;i<N;i++) { a1.push_back(i); b1.push_back(i); }
    	for (i=0;i<N;i++) { a2.push_back(i); b2.push_back(i); }
     
    	debut=clock();
     
    	pthread_t t1,t2;		
     
    	pthread_create(&t1,NULL,thread1,NULL);
    	#ifdef MULTITHREAD
    		pthread_create(&t2,NULL,thread2,NULL);		
    	 #endif
     
    	pthread_join(t1,NULL);
    	#ifdef MULTITHREAD
    		pthread_join(t2,NULL);
    	#endif
     
    	fin=clock();
    	cout<<"Temps : "<<(fin-debut)/1000/NBCPU<<" millisecondes"<<endl;
    	cout <<"Test1 : "<<test1<<"    test2 : "<<test2<<"\n";;
     
    	cout<<endl<<endl;
     
    	return 0;
    }

    Le Makefile qui va avec:

    CFLAGS = -O2 -lpthread
    CC = g++

    # FLAGS:
    # MULTITHREAD : lance deux threads; sinon n'en lance qu'un seul
    # TBB : utilise l'allocateur de la bibliothèque multithread d'Intel

    default:
    $(CC) $(CFLAGS) mt_tbb.cpp -o mt_tbb_off_1thread.exe -DNULIX
    $(CC) $(CFLAGS) mt_tbb.cpp -o mt_tbb_off_2thread.exe -DNULIX -DMULTITHREAD

    $(CC) $(CFLAGS) mt_tbb.cpp -o mt_tbb_on_1thread.exe -DUSE_TBB -DNULIX -ltbb -ltbbmalloc
    $(CC) $(CFLAGS) mt_tbb.cpp -o mt_tbb_on_2thread.exe -DUSE_TBB -DNULIX -DMULTITHREAD -ltbb -ltbbmalloc


    echo ======Bench=======;
    ./mt_tbb_off_1thread.exe
    ./mt_tbb_off_2thread.exe
    ./mt_tbb_on_1thread.exe
    ./mt_tbb_on_2thread.exe

    Et enfin la sortie produite, on l'on voit que la version avec allocateur standard prend tout son temps, tandis que la version avec TBB mets le meme temps qu'il y ait un ou deux threads s'éxécutant:
    (éxécuté sur un Intel CoreDuo)

    :~/test$ make
    g++ -O2 -lpthread mt_tbb.cpp -o mt_tbb_off_1thread.exe -DNULIX
    g++ -O2 -lpthread mt_tbb.cpp -o mt_tbb_off_2thread.exe -DNULIX -DMULTITHREAD
    g++ -O2 -lpthread mt_tbb.cpp -o mt_tbb_on_1thread.exe -DUSE_TBB -DNULIX -ltbb -ltbbmalloc
    g++ -O2 -lpthread mt_tbb.cpp -o mt_tbb_on_2thread.exe -DUSE_TBB -DNULIX -DMULTITHREAD -ltbb -ltbbmalloc
    echo ======Bench=======;
    ======Bench=======
    ./mt_tbb_off_1thread.exe
    Thread1!
    Verification de C:
    Fin thread 1.
    Temps : 910 millisecondes
    Test1 : 11 test2 : 0


    ./mt_tbb_off_2thread.exe
    Thread1!
    Thread2!
    Verification de D:
    Fin thread 2.
    Verification de C:
    Fin thread 1.
    Temps : 16350 millisecondes
    Test1 : 11 test2 : 22


    ./mt_tbb_on_1thread.exe
    Thread1!
    Verification de C:
    Fin thread 1.
    Temps : 920 millisecondes
    Test1 : 11 test2 : 0


    ./mt_tbb_on_2thread.exe
    Thread1!
    Thread2!
    Verification de C:
    Fin thread 1.
    Verification de D:
    Fin thread 2.
    Temps : 1025 millisecondes
    Test1 : 11 test2 : 22

  7. #7
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    tbb ne donne pas des conteneur??

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

Discussions similaires

  1. Singleton - multithread - protection donnees - conteneurs stl
    Par sone47 dans le forum Threads & Processus
    Réponses: 8
    Dernier message: 18/01/2013, 11h51
  2. STL list insertion Multithreading
    Par pavel dans le forum C++
    Réponses: 2
    Dernier message: 17/03/2010, 14h00
  3. [Win32]App multithread
    Par billyboy dans le forum Windows
    Réponses: 5
    Dernier message: 25/09/2003, 09h57
  4. [Kylix] [BCB] pb avec la STL
    Par pykoon dans le forum EDI
    Réponses: 1
    Dernier message: 29/12/2002, 12h56
  5. Multithreading sous HP Ux 11
    Par pykoon dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 18/10/2002, 23h36

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