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

Boost C++ Discussion :

[Boost Thread] Calcul dans un thread puis stockage du resultat


Sujet :

Boost C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Points : 185
    Points
    185
    Par défaut [Boost Thread] Calcul dans un thread puis stockage du resultat
    Bonjour,

    je débute tout juste dans les boost thread, j'ai qques notions de multi-threading, j'ai fait qques recherches sur le sujet.
    Mais la j'ai un problème conceptuel

    Voila ce que je veux faire.
    J'ai deux tables CALENDARS et DATES.
    CALENDARS liste les calendriers de pays avec leurs noms (France, Allemagne etc).
    DATES correspond au jours fériés de ces calendriers.

    J'ai donc une fonctions LoadCalendars qui va recherché l'ensemble de mes calendriers ainsi que leurs noms.
    Puis une fonction LoadCalendar qui charge un calendrier particulier en memoire et le stock dans une map statique de calendriers. (map<std::string, Calendar*>)

    Voila déjà mon code non "entièrement" multithreadé:
    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
    void OracleCalendarRepository::LoadCalendars() {
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("+LoadCalendars"));
      // Bouml preserved body begin 0001FA03
    isDb("OracleCalendarRepository");
    try {
        otl_stream selectCalendars (50, "select NAME_, IDCALENDAR_ from CALENDARS order by NAME_ ASC", *db);
    
        int idcalendar;
        std::string name;
        while (!selectCalendars.eof()) {
            boost::mutex::scoped_lock
            lock(loadCalendarsMutex);
            selectCalendars >> name >> idcalendar;
            Calendar* calendar = LoadCalendar(idcalendar); //Chargement de mon calendrier.
            Calendar::insert(name, calendar);
        }
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);
        support::exception::dao::DataRetrievalFailureDaoException exptErr(strErr);
        throw exptErr;
    }
      // Bouml preserved body end 0001FA03
    
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendars"));
    }
    
    /**
     * Load a single calendar from the Oracle database
     * @param the id of the calendar in the database
     */
    void LoadCalendar(int id) {
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("+LoadCalendar"));
      // Bouml preserved body begin 0001FA83
    isDb("OracleCalendarRepository");
    Calendar* calendar = NULL;
    try {
        otl_stream selectCalendars (100, "select TO_CHAR(DATE_, \'YYYYMMDD\"T\"HH24MISS\'), EVENT_ from DATES where IDCALENDAR_ = :f<int> order by DATE_ ASC", *db);
        selectCalendars << id;
    
        std::string name;
        int ievent;
        calendar = new Calendar(id, this);
        while (!selectCalendars.eof()) {
            selectCalendars >> name >> ievent; 
            calendar->insertDate(boost::posix_time::from_iso_string(name.c_str()), ievent);
        }
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);
        support::exception::dao::DataRetrievalFailureDaoException exptErr(strErr);
        throw exptErr;
    }
    return calendar;
      // Bouml preserved body end 0001FA83
    
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendar"));
    }
    Vous noterez la présence d'un lock qui s'explique par le fait que cette fonction est appelé dans un thread en parrallèle de mon application et que je ne veux pas faire plusieurs inserts en meme temps. Je ne lance LoadCalendars qu'une fois à la main mais c'est juste une question de sécurité. (Puis je voulais tester les locks )

    Comme vous vous en doutez, ce qui prend le plus de temps dans cette fonction est l'appel à la fonction LoadCalendar.
    J'aurais donc voulu que mon chargement de unitaire calendrier se fasse en parallèle, donc que je lance plusieurs LoadCalendar en même temps puis que je stocke le résultat de chacune à la fin dans ma map.

    Mon problème est que je ne sais absolument pas comment faire??!

    Concrètement, je veux pouvoir lancer plusieurs threads en meme temps, recupérer les resultats de tous et le stocker.

    EDIT:
    PS: Il faut que la gestion d'exception marche toujours entre les threads afin de pouvoir remonter l'info à l'utilisateur (sinon c'est pas drole)

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Points : 185
    Points
    185
    Par défaut
    alors voila ou j en suis:

    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
    /**
     * Load a single calendar from the Oracle database
     * @param the id of the calendar in the database
     */
    void LoadCalendar(std::string name, int id, otl_connect *db, OracleCalendarRepository *calRepo) {
    //LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("+LoadCalendar"));
      // Bouml preserved body begin 0001FA83
    Calendar* calendar = NULL;
    try {
        //otl_stream selectCalendars (100, "select TO_CHAR(DATE_, \'YYYYMMDD\"T\"HH24MISS\'), EVENT_ from DATES where IDCALENDAR_ = :f<int> order by DATE_ ASC", *db);
        otl_stream selectCalendars (100, "select TO_CHAR(DATE_, \'YYYYMMDD\"T\"HH24MISS\'), EVENT_ from SORT_ADM.SORT_E_CLOSEDATE where IDCALENDAR_ = :f<int> order by DATE_ ASC", *db);
        selectCalendars << id;
     
        std::string name;
        int ievent;
        calendar = new Calendar(id, calRepo);
        while (!selectCalendars.eof()) {
            selectCalendars >> name >> ievent; 
            calendar->insertDate(boost::posix_time::from_iso_string(name.c_str()), ievent);
        }
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        /*std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);*/
        support::exception::dao::DataRetrievalFailureDaoException exptErr("Oracle Error");
        throw exptErr;
    }
    Calendar::insert(name, calendar);
      // Bouml preserved body end 0001FA83
     
    //LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendar"));
    }
     
    /**
     * Loads all the calendars from the Oracle database
     */
    void OracleCalendarRepository::LoadCalendars() {
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("+LoadCalendars"));
      // Bouml preserved body begin 0001FA03
    isDb("OracleCalendarRepository");
    try {
        otl_stream selectCalendars (50, "select NAME_, IDCALENDAR_ from CALENDAR order by NAME_ ASC", *db);
     
        int idcalendar;
        std::string name;
        boost::thread_group threadGroup;
        while (!selectCalendars.eof()) {
            selectCalendars >> name >> idcalendar; 
            threadGroup.create_thread(boost::bind(&LoadCalendar, name, idcalendar, db, this));
        }
        threadGroup.join_all();
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);
        support::exception::dao::DataRetrievalFailureDaoException exptErr(strErr);
        throw exptErr;
    }
      // Bouml preserved body end 0001FA03
     
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendars"));
    }
    Ca a l air de pas trop mal aller.
    Le pb c'est que je peux pas avoir trop de connections SQL en meme temps et donc ca plante.
    J'aimerais donc me limiter à 5 connections simultanées.
    Je fais comment?

    J'ai vu l'utilisation de condition et autres mais je suis un peu perdu.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Points : 185
    Points
    185
    Par défaut
    voila le bout de code qui marche:

    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
    /**
     * Load a single calendar from the Oracle database
     * @param the id of the calendar in the database
     */
    void LoadCalendar(std::string name, int id, otl_connect *db, OracleCalendarRepository *calRepo) {
     
    com::fxoverlay::business::time::Calendar* calendar = NULL;
    try {
     
        otl_stream selectCalendars (100, "select TO_CHAR(DATE_, \'YYYYMMDD\"T\"HH24MISS\'), EVENT_ from DATES where IDCALENDAR_ = :f<int> order by DATE_ ASC", *db);
        {
            boost::mutex::scoped_lock lock(loadCalendarsMutex);
            selectCalendars << id;
        }
        std::string name;
        int ievent;
        calendar = new Calendar(id, calRepo);
        while (!selectCalendars.eof()) {
            selectCalendars >> name >> ievent; 
            calendar->insertDate(boost::posix_time::from_iso_string(name.c_str()), ievent);
        }
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        /*std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);*/
        support::exception::dao::DataRetrievalFailureDaoException exptErr("Oracle Error");
        throw exptErr;
    }
    Calendar::insert(name, calendar);
     
     
    //LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendar"));
    }
     
    /**
     * Loads all the calendars from the Oracle database
     */
    void OracleCalendarRepository::LoadCalendars() {
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("+LoadCalendars"));
      // Bouml preserved body begin 0001FA03
    isDb("OracleCalendarRepository");
    try {
        otl_stream selectCalendars (50, "select NAME_, IDCALENDAR_ from CALENDAR order by NAME_ ASC", *db);
     
        int idcalendar;
        std::string name;
        boost::thread_group threadGroup;
        while (!selectCalendars.eof()) {
            selectCalendars >> name >> idcalendar;
            threadGroup.create_thread(boost::bind(&LoadCalendar, name, idcalendar, db, this));
            //LoadCalendar(name, idcalendar, db, this);
        }
        threadGroup.join_all();
    }
    catch (otl_exception& p){ // intercept OTL exceptions
        std::string strErr = formatOracleError(p);
        LOG4CXX_ERROR(OracleCalendarRepository::logger, strErr);
        support::exception::dao::DataRetrievalFailureDaoException exptErr(strErr);
        throw exptErr;
    }
      // Bouml preserved body end 0001FA03
     
    LOG4CXX_DEBUG(OracleCalendarRepository::logger, _T("-LoadCalendars"));
    }
    par contre je comprend pas pourquoi mon code est bien plus long que si je le lance avec un seul thread.
    Qd je dis bien plus long c est quasi triple (je passe de 40sc à 1mn50 quasiment). Je passe de 5 thread à 35 threads.
    Alors que dans un cas le processeur est utilise a 50% et en multi thread 100%.

    QQun pour m expliquer ce curieux dilemne?

  4. #4
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Le multithread est adapté quand plusieurs traitements ont besoin de resources différentes.... Et que l'accès à ces ressources est plus lent que le traitement lui-même.

    Sinon, à coup sur, plusieurs threads c'est plus long qu'un seul.
    Et là... le pire, c'est que tu crées tes threads "à la volée". Ca doit être l'élément le plus lent. La création d'un thread coûte très cher.
    En même temps, si la fonction n'est appelée qu'une fois, ca changera pas grand chose.

    Je ne sais pas quelle DB tu utilises, ni quel driver, ni comment le SQL est géré dans cette DB... Mais on va dire que c'est LA resource lente. Ca à l'air d'être du "Oracle"...
    Dans tous les cas, je ne vois pas trop l'utilité du 'loadCalendarsMutex'. D'après ce que je lis, il empeche que le SQL-call soit parallèlisable, et donc, réduit à néant l'interêt du multi-thread.

    De plus, une connection DB n'est (d'habitude) pas parallèlisable.... Et je ne suis pas sur que le driver ne mette pas des locks de manière interne de la même façon (en particulier sur les result-set). Il te faut donc plusieurs connections à la DB.

    Personnellement, j'aurai fait un seul thread avec un seul call SQL genre:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select c.IDCALENDAR_, c.NAME_, TO_CHAR(d.DATE_, 'YYYYMMDD HH24MISS'), d.EVENT_ from DATES d inner join CALENDAR c on c.IDCALENDAR_ = d.IDCALENDAR_ order by c.NAME_ ASC, d.DATE_ ASC
    Et utilisation du calendrier courant si l'ID n'a pas changé, ou création d'un nouveau calendrier (après insertion du courant) si il a changé....
    A noter qu'il n'y a aucune prise en charge du timezone dans le call ci-dessus, et que la réponse est donc dans la timezone de la Database (il faut s'assurer qu'elle correspond bien à la timezone utilisée par boost pour la transformation en date)

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Points : 185
    Points
    185
    Par défaut
    hum...




    rien à ajouter.

    Merci

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

Discussions similaires

  1. Ajouter un thread deamon dans un thread
    Par Mengué georges dans le forum Collection et Stream
    Réponses: 0
    Dernier message: 28/04/2010, 14h16
  2. Réponses: 5
    Dernier message: 28/03/2010, 22h47
  3. Exception dans un thread puis NullException
    Par Nasky dans le forum Concurrence et multi-thread
    Réponses: 3
    Dernier message: 17/03/2007, 19h18
  4. [THREAD] WSAEventSelect dans plusieurs threads
    Par Invité dans le forum Visual C++
    Réponses: 3
    Dernier message: 05/03/2007, 14h41
  5. [Thread] DB dans un thread
    Par Pedro dans le forum Bases de données
    Réponses: 5
    Dernier message: 02/06/2005, 13h14

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