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 :

std::thread, comportement innattendu.


Sujet :

Threads & Processus C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut std::thread, comportement innattendu.
    Salut,
    je souhaite faire ceci :

    -Endormir un thread jusqu'à qu'au moins un événement soit généré.

    -Lorsque le thread est réveillé, l'endormir pendant quelque temps pour éviter les appels trop nombreux à lock et puis traiter un événement et ainsi de suite.

    -Ensuite je souhaite bloqué les autres threads le temps du traitement d'un événement et les réveillé lorsque l'événement est traité.

    J'ai donc fait quelque chose comme ceci.

    Code cpp : 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
     
    #ifndef ODFAEG_ENTITY_SYSTEM_HPP
    #define ODFAEG_ENTITY_SYSTEM_HPP
    #include <condition_variable>
    #include <mutex>
    #include <thread>
    #include "export.hpp"
    #include <chrono>
    /**
    *\namespace odfaeg
    * the namespace of the Opensource Development Framework Adapted for Every Games.
    */
    namespace odfaeg {
    /**
    * \file entitySystem.h
    * \class EntitiesSystem
    * \brief base class of all entities systems of the odfaeg.
    * \author Duroisin.L
    * \version 1.0
    * \date 1/02/2014
    */
    class ODFAEG_CORE_API EntitySystem {
    public :
        /**
        *\fn EntitySystem ()
        *\brief constructor.
        */
        EntitySystem () : needToUpdate(false) {
            running = false;
            g_notified = true;
        }
        /**
        *\fn void launch()
        *\brief launch the thread to update every entities of the entity system.
        */
        void launch () {
            running = true;
            m_thread = std::thread (&EntitySystem::run, this);
     
        }
        /**
        *\fn void update()
        *\brief function called when we need to update the entities, this function block the current thread until it's finished.
        */
        void update () {
            if (!needToUpdate) {
                g_notified = false;
                needToUpdate = true;
                g_signal.notify_one();
                std::unique_lock<std::mutex> locker (g_lock_update);
                g_signal.wait(locker, [&](){return g_notified;});
            }
        }
        /**
        *\fn void run()
        *\brief this function block this thread until we need to update the entities by calling the update function.
        * or if we want to stop the thread.
        */
        void run () {
     
            while (running) {
                std::chrono::microseconds dura(100);
                std::this_thread::sleep_for(dura);
                std::unique_lock<std::mutex> locker(g_lock_update);
                g_signal.wait(locker, [&](){return needToUpdate || !running;});
                if (needToUpdate)
                    onUpdate();
                g_notified = true;
                needToUpdate = false;
                g_signal.notify_all();
            }
        }
        /**
        *\fn bool isRunning()
        *\brief tells is the thread is running.
        *\return true if the thread is running.
        */
        bool isRunning () {
            return running;
        }
        /**
        *\fn void stop()
        *\brief stop this thread.
        */
        void stop () {
            running = false;
            g_signal.notify_all();
        }
        /**
        *\fn void onUpdate()
        *\brief function to refefines to updates the entities.
        */
        virtual void onUpdate() = 0;
    private :
        std::thread m_thread; /**< an internal thread which updates the entities*/
        bool running, needToUpdate, g_notified; /**< tells if the thread is running, if the entities need to be update by the thread, and, if the thread have finished to update the entities.*/
        std::condition_variable g_signal; /**<condition variable used for the primitive synchronisation of the thread.*/
        std::mutex g_lock_update; /**<mutex used in the condition variable to avoid concurrent access to a variable between different threads*/
    };
    }
    #endif // ENTITY_SYSTEM

    Cependant cela ne produit pas le comportement que je désire, je m'explique :

    Les threads sont endormis avant que je fasse l'appel à g_signal.wait dans la boucle du thread, ce qui fais chuter mon FPS. :/ (Hors ça, je ne veux pas, je veux que les threads soit mis en attente après ce délai ci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     std::chrono::microseconds dura(100);
     std::this_thread::sleep_for(dura);

    Et j'ai un crash également avec Xlib, voici ce qu'il m'affiche ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    [xcb] Unknow request in queue while dequeuing.
    [xcb] Most likely this is a multi-thread client and XInitThreads has not been called
    [xcb] Abording, sorry about that.
    ODFAEG-DEMO: ../../src/xcb_io.c:179: dequeue_pending_request: Assertion '!xcb_xlib_unknown_req_in_deq' failed.
    Bref, je ne sais plus trop quoi faire. :/

  2. #2
    Membre éprouvé Avatar de KsassPeuk
    Homme Profil pro
    Ingénieur Chercheur
    Inscrit en
    Juillet 2013
    Messages
    138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Chercheur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2013
    Messages : 138
    Par défaut
    Lu'!

    Pourquoi locker ? Dans le modèle que tu veux faire, il semble que la problématique soit "j'ai un pool de worker capable d'exécuter des tâches, je veux qu'ils se les distribuent de manière à peu près équitable pour les exécuter". En gros le but : avoir un conteneur partagé où chaque thread vient piocher au besoin. Si tu as une queue-lock-free (boost en propose pas mal) et que chacun vient piocher dedans, ça ne lockera pas. Si tu veux éviter l'attente active par la suite, c'est à toi de voir si tu veux juste introduire de la latence (sleep) ou du système wait/signal mais du coup, ça reste hors du conteneur.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Lu'!

    Pourquoi locker ? Dans le modèle que tu veux faire, il semble que la problématique soit "j'ai un pool de worker capable d'exécuter des tâches, je veux qu'ils se les distribuent de manière à peu près équitable pour les exécuter".
    Si je ne lock pas, j'ai des affichages de "bout" de scene sur mes composants graphiques, et si je ne lock pas je dois faire une copie du conteneure ce qui n'est pas mieux. :/

    Bref, j'ai enlevé carrément les threads. (en fait j'ai une variable booléenne que je met à true et à false selon que je veille faire ça dans un autre thread ou pas)

    Et sans thread ça tourne bien. (Et j'ai le même FPS)

    Je pense donc que je vais foutre au diable cette implémentation, xLib ne semble pas supporté les locks.

    J'ai pourtant fais un XInitThreads mais ça ne résouds pas le problème.

    PS : de plus si je ne lock pas je risque que deux workers accèdent au conteneure en même temps et donc..., d'avoir des crashs.

  4. #4
    Membre éprouvé Avatar de KsassPeuk
    Homme Profil pro
    Ingénieur Chercheur
    Inscrit en
    Juillet 2013
    Messages
    138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Chercheur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2013
    Messages : 138
    Par défaut
    ... Ce n'est pas parce que tu ne lockes pas que tu ne peux pas avoir d'exclusion mutuelle.
    C'est précisément ce que j'ai mis dans mon post précédent. Pour ce qui est des tâches à effectuer, tu prends un conteneur lock-free, et chaque thread vient piocher sa tâche à effectuer. Si ta conception est bien réalisée, ces tâches sont indépendantes et donc ne doivent pas entrer en conflit.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bref, je préfère utiliser une implémentation non "threadée" dans ce cas plutôt que de piocher dans un contenaire, car sinon je dois faire des copies de ce qu'il y a dans le contenaire lock free, le modifier avec le worker et update le contenaire de l'autre thread quand le worker à terminé, sans savoir si cela sera plus performant à cause des copies de pointeurs, bref..., je peux peut être par contre économiser du CPU, en endormant le thread du worker...

    A voir...

    PS : de plus lors de la copie je dois lock, pour pas que le thread d'affichage vienne piocher dans le conteneur en même temps que le worker vient piocher dedans donc, je ne pense pas que l'on puisse se passer d'un lock.

    Donc ça va faire pas mal de lock si je dois lock le mutex à chaque affichage, pour cela que j'ai essayé une autre alternative, qui, met à jour le conteneure et bloque le thread d'affichage tout les x millisecondes jusqu'à que le conteneure soit mis à jour.

    Mais, ça ne fonctionne pas.
    Dernière modification par Invité ; 05/12/2014 à 16h42.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Ca y est, j'ai résolu mon problème!

    En fait il fallait utiliser cette fonction : wait_for

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    std::chrono::milliseconds dura(100);
    std::unique_lock<std::mutex> locker(g_lock_update);
    g_signal.wait_for(locker, dura, [&](){return needToUpdate || !running;});
    if (needToUpdate)
        onUpdate();
    g_notified = true;
    needToUpdate = false;
    g_signal.notify_all();

    Ainsi ceci n'effectue la tâche que tout les 0.1 secondes donc, ça bloque le mutex que tout les 0.1 seconds et même chose pour mes autres thread.

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

Discussions similaires

  1. [std::thread] Algorithme plus lent que en simple thread
    Par Trademark dans le forum Threads & Processus
    Réponses: 24
    Dernier message: 17/04/2013, 10h52
  2. std::thread et contrôle du thread créé
    Par progPseud dans le forum Threads & Processus
    Réponses: 4
    Dernier message: 01/02/2013, 19h57
  3. Erreur avec std::thread (C++11)
    Par gbdivers dans le forum Qt Creator
    Réponses: 0
    Dernier message: 14/08/2012, 11h09
  4. std::thread et erreur r6010
    Par swain.dakota dans le forum Threads & Processus
    Réponses: 3
    Dernier message: 02/08/2012, 22h15

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