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 :

questions sur les mutex, les singletons, boost etc.


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé Avatar de kain_tn
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 861
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 861
    Par défaut questions sur les mutex, les singletons, boost etc.
    Bonjour.


    Je me retrouve face à un problème de conception...

    J'aimerais développer une classe servant à écrire des données dans un fichier (RAII)
    Seulement cette classe peut être accédée par plusieurs threads et je voudrais éviter que plus d'un thread à la fois modifie le fichier.

    L'idée que j'avais était de créer une fifo, et de faire en sorte que les threads poussent des données dans la fifo, tandis qu'un autre thread la dépilerait toutes les T périodes et écrirait les données dans le fichier.

    L'idée vous paraît-elle viable? Que feriez vous sinon?

    Pour ce qui est d'accéder à la fifo, il paraît évident qu'il ne faut pas que tous les threads y accèdent en même temps. Je pensais donc avoir recours à des mutex. J'ai commencé à regarder ceux de boost, mais j'avoue être un peu perdu dans la documentation (en gros, peu de cas pratiques, mais beaucoup de théorie...). Encore une fois, est-ce une bonne idée?

    A priori, ma fifo doit être statique pour être accédée de n'importe où non? Est-il préférable de la gérer dans une classe (singleton) ? Est-ce compatible (thread safe) avec ce que je veux faire plus haut?

    Bref, je ne sais pas si je suis très clair dans mes explications mais n'hésitez pas à me poser des questions!

    Merci d'avance!

  2. #2
    Membre éprouvé Avatar de kain_tn
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 861
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 861
    Par défaut
    Bon eh bien en fait j'ai résolu mon problème

    Je ne suis pas passé par les mutex de boost mais j'ai créé ma propre classe de mutex et de lock:

    En gros, je crée ma classe Writer qui est un singleton:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Writer: public Singleton<Writer>
    Ensuite je crée une classe Mutex, qui contient un booléen mLocked et trois méthodes isLock(), lock() et unlock():
    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
     
     class Mutex{
     
    	private:
    		bool mLocked;
     
    	public:
    		Mutex()
    		:mLocked(false){
    		}
     
    		bool lock();
    		bool unlock();
    		bool isLocked()const;
     };
    Je crée également une classe Lock, qui prend une référence sur un object Mutex dans son constructeur:
    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
     
     class Lock{
     
     	private:
     		Mutex& mMutex;
     
     		void lock(Mutex& mutex){
     			mutex.lock();
     		}
     
     		void unlock(Mutex& mutex){
     			mutex.unlock();
     		}
     
     	public:
     		Lock(Mutex& mutex)
     		:mMutex(mutex){
     			lock(mutex);
     		}
     
     		~Lock(){
     			unlock(mMutex);
     		}
     
     };
    1. Le constructeur invoque la méthode lock() sur l'objet Mutex
    2. Le destructeur invoque la méthode unlock() sur l'objet Mutex


    Ainsi, je m'assure que le Mutex est bien déverrouillé à la mort de l'objet Lock.

    Je crée également une classe File, qui fonctionne sur le même principe; à savoir fopen() dans le constructeur, et fclose() dans le destructeur.

    Enfin, ma classe Writer contient une fifo (std::queue) ainsi qu'un objet Mutex. Elle contient également les méthodes push() et write().
    Ces deux méthodes ne se lancent que si Mutex.isLocked() vaut false.
    Elle instancient ensuite un objet Lock Cet objet va donc verrouiller le mutex et le déverrouiller dès que la méthode en cours sera terminée.
    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
     
    bool push(const std::string& data){
     
    			if( !mMutex.isLocked() ){
     
    				Lock l(mMutex); // Lock the mutex
                                    if( !mMutex.isLocked() )
    					return false;
     
    				mData.push( data );
    				return true;
    			}
     
    			return false;
    		}
     
    ...

  3. #3
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Tu as l'air de t'en être sorti tout seul, félicitations .

    Toutefois, j'attire ton attention sur plusieurs choses :
    - tu as un peu réinventé la roue, il y a déjà tout ça dans boost.
    - comment fais-tu effectivement l'écriture dans le fichier ? Il y a un thread en attente active, ou quelque chose du genre ?
    - l'appelant doit à chaque fois vérifier que push a réussi, gérer des retry lui-même.

    Le premier point n'est pas très important.

    Pour le deuxième, il faudrait que tu passes par une condition variable, avec un réveil du thread chargé d'écrire dans le fichier, uniquement lorsque des données ont été rajoutées dans la queue (logiquement, dans la méthode push).

    Pour le troisième, j'ai un peu de mal à suivre l'idée. Tes threads font des choses critiques, et ne peuvent pas être bloqués plus d'un certain temps ? Si ce n'est pas le cas, autant mettre une attente infinie sur le mutex. Vu qu'il ne protège pas une ressource externe, mais seulement la queue, tu es tranquille, sauf erreur de programmation, il sera libéré à un moment ou un autre. Push réussira toujours, et tu n'auras pas à te préoccuper de gérer des réessais dans l'appelant à chaque push.

  4. #4
    Membre éprouvé Avatar de kain_tn
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 861
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 861
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Toutefois, j'attire ton attention sur plusieurs choses :
    - tu as un peu réinventé la roue, il y a déjà tout ça dans boost.
    Oui je sais, mais le faire moi même m'a aidé à comprendre comment fonctionnent ces composants ainsi que la bibliothèque
    De plus, même si les options sont limitées comparées à boost, je ne dépends pas d'une bibliothèque externe.
    Citation Envoyé par white_tentacle Voir le message
    - comment fais-tu effectivement l'écriture dans le fichier ? Il y a un thread en attente active, ou quelque chose du genre ?
    Oui. Il y a un thread dédié à l'écriture. Lorsqu'il se réveille, il dépile la fifo.
    Citation Envoyé par white_tentacle Voir le message
    - l'appelant doit à chaque fois vérifier que push a réussi, gérer des retry lui-même.
    Oui. C'est un des points que je veux améliorer mais chaque chose en son temps (par contre, si tu as une idée... )

    Citation Envoyé par white_tentacle Voir le message
    Pour le deuxième, il faudrait que tu passes par une condition variable, avec un réveil du thread chargé d'écrire dans le fichier, uniquement lorsque des données ont été rajoutées dans la queue (logiquement, dans la méthode push).
    Pour la condition, je ne pense pas que ce soit un problème: en fait j'ai un système de "listener" sur mes "loggers", et je peux donc être prévenu si nécessaire qu'il y a eu un appel à push().

    Citation Envoyé par white_tentacle Voir le message
    Pour le troisième, j'ai un peu de mal à suivre l'idée. Tes threads font des choses critiques, et ne peuvent pas être bloqués plus d'un certain temps ? Si ce n'est pas le cas, autant mettre une attente infinie sur le mutex. Vu qu'il ne protège pas une ressource externe, mais seulement la queue, tu es tranquille, sauf erreur de programmation, il sera libéré à un moment ou un autre. Push réussira toujours, et tu n'auras pas à te préoccuper de gérer des réessais dans l'appelant à chaque push.
    OK, je vois un peu l'idée, mais tu ferais ça comment? Avec un while par exemple? Est-ce que ça ne risque pas de bouffer toutes les ressources du processeur?
    Tu verrais un truc comme ça?
    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
     
    bool push(const std::string& data){
     
    	while( true ){
     
    		if( !mMutex.isLocked() ){
     
    			Lock l(mMutex); // Lock the mutex
    			if( !mMutex.isLocked() )
    				return false;
     
    			mData.push(data);
    			return true;
    		}else
    			sleep(2);
    	}
    }

    Merci d'avoir pris le temps de me lire en tous cas!

  5. #5
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Tu n'a pas besoin de while, ni d'attente active. Quand tu demandes à bloquer un mutex, si celui-ci est déjà bloqué, le thread est suspendu, il ne fait rien d'autre qu'attendre que le mutex se libère (et ce, sans consommer de processeur).

    Bien sûr, cela n'est vrai que si tu n'as pas mis de timeout à ton lock. Mais le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Lock l(mMutex); // Lock the mutex
    mData.push(data);
    return true;
    devrait suffire (à condition, bien sûr, que tu n'aies pas précisé de timeout sur ton lock, auquel cas tu n'es pas garanti que ton mutex est locké après le lock !)

  6. #6
    Membre éprouvé Avatar de kain_tn
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 861
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 861
    Par défaut
    Je n'ai pas mis de timeout à mon lock, non
    Merci pour tes réponses, ça m'a beaucoup aidé!

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

Discussions similaires

  1. [XL-2010] Question sur Excel et les "Array-Entered Formulas" avec accolades
    Par balteo dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 06/08/2010, 19h33
  2. Question sur vista et les Exe
    Par restesouple dans le forum Windows Forms
    Réponses: 8
    Dernier message: 07/11/2007, 14h57
  3. [Java] Question sur Java et les états.
    Par Cassios dans le forum Autres outils décisionnels
    Réponses: 6
    Dernier message: 19/02/2007, 17h37
  4. [VBA-E]Encore une question sur csv et les dates
    Par vovor dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 14/10/2006, 10h43
  5. Question sur exports et les classes (pour une dll)
    Par DjPoke dans le forum Langage
    Réponses: 7
    Dernier message: 08/08/2005, 19h25

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