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 :

Synchronisation de Threads avec un systeme de signal/event


Sujet :

Threads & Processus C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut Synchronisation de Threads avec un systeme de signal/event
    Bonjour,

    Desole pour le nom du topic mais je ne sais pas trop comment appeller ce que je veux faire :p

    Bref, je suis en train de me prendre la tete sur un soucis de synchro inter threads.

    Ce que je veux faire me semble pourtant assez simple mais je n'arrive pas a trouver une solution fiable a 100%. Je fais donc appelle a vous en esperant que vous puissiez m'eclairer

    Je suis en train de coder un server Multi Thread. Pour faire simple il y a deux threads :
    Le premier s'occupe du network (le network).
    Le second du traitement des donnees (le core).

    Ce que je veux pouvoir faire :
    Le thread de traitement de donnee doit pouvoir attendre une instruction. Quand le network push une instruction dans le queue du core. Le network doit reveiller le core. Jusqu'ici rien de bien complique avec des conditions !

    Cependant je voudrais pouvoir empiler les actions du network.

    Comme si dessous :

    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
     
    class GThreadTest
    {
    private:
    	Tools::Thread<GThreadTest>	_thread1;
    	Tools::Thread<GThreadTest>	_thread2;
    	Tools::Signal			_signal;
    	double _compteur;
     
    public:
    	void	thread1()
    	{
    		this->_signal.active();
    		this->_signal.active();
    		this->_signal.active();
    		this->_signal.active();
    		std::cout << "Signaux OK" << std::endl;
    	}
     
     
    	void	thread2()
    	{
    		Sleep(1000);
    		this->_signal.wait();
    		this->_signal.wait();
    		this->_signal.wait();
    		this->_signal.wait();
    	}
     
    	GThreadTest()
    		: _thread1(), _thread2()
    	{
    		this->_thread1.start(this, &GThreadTest::thread1);
    		this->_thread2.start(this, &GThreadTest::thread2);
    		this->_thread1.join();
    		this->_thread2.join();
    	};
    };
    On active 4 fois le signal.
    Le second thread doit alors passer les 4 wait avec succes.


    Le code doit etre portable linux/windows le namespace "Tools" contient mes abstractions.

    Avez vous une idee d'algorithme avec des mutex et des conds pour arriver a ce resultat ?

    Merci d'avance

    Bonne soiree

  2. #2
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    je ne comprends pas la question.
    Cela dit, il est tard et j'ai eu une rude journée, peut-être est-ce moi qui ne suit pas clair, et non la question

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Excuse moi

    Je vais essayer de faire clair et concis.

    J'ai un thread A qui envoi des messages a un thread B grace a une stack.

    Si B n'a rien a faire il se bloque et attend un ordre de A pour repartir.

    Cependant B ne doit pas faire d'attente active il doit reste bloque dans un Mutex ou une Condition!

    Mon probleme c'est que je ne vois pas comment faire en sorte que les ordres de A ne soient perdus pendant que B est actif !

    Je peux faire avec un if et un compteur mais dans ce cas A pourrait envoyer un ordre pendant que B est entre le if et le wait et dans ce cas B resterait bloque.

    Une idee d'algorithme ?

    Merci pour ton aide

  4. #4
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Je ne suis toujours pas sûr de comprendre ton problème, mais peut-être une piste:
    Dans une architecture lanceur/receveur, la FIFO appartient quasiment toujours au receveur: le lanceur envoie son message, le receveur le reçoit et le stocke dans sa FIFO. En général c'est un troisième thread qui "consomme" la FIFO, mais ce n'est pas toujours obligé, ça dépend des contraintes.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Je comprends pas tres bien l'interet du 3eme thread ?

    En fait mon receveur doit pouvoir dormir tant que le lanceur lui donne pas de travail.

    Par contre si le lanceur lui donne beaucoup de travail il doit d'abord effectuer toutes les actions avant de retourner dormir.

    Mais j'ai peur que le receveur reste en someil si le lanceur donne du travail alors que le receveur est dans entre le "test" et le "wait".
    Dans ce cas le receveur se met en wait alors que le lanceur lui a donne une tache. Il faudra alors attendre la tache suivante pour que le receveur se reveil et effecter les deux taches.

    C'est ce moment ou le receveur est entre le "test" et le "wait" qui me prend la tete !

    Par contre merci pour l'idee de rajouter une FIFO propre au receveur ca devrait fluidifier ma communication interthread quand elle est chargee ! Merci

  6. #6
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    en général, le receveur est séparé en 2 threads: le premier reçois les messages et les stocke, et le deuxième les consomme. L'avantage est que ça facilite les évolutions (par exemple si on veut ajouter d'autres lanceurs, si on pas ps un thread dédié à "nourrir" la FIFO, c'est vite un casse-tête). e plus, ça simplifie les problèmes de gestion d'accès à la FIFO: le receveur peut contineur à recevoir des messages pendant qu'il est en train d'en traiter un, sans avoir besoin de mettre en place un système de mutex etc. D'autant plus que s'il est nécessaire de se poser la question de "un thread ou deux?", une fois qu'on en a deux, le troisième ne coûte rien.

    Par contre, généralement, c'est une erreur de stocker des messages dans le lanceur. Normalement, le lanceur ne fait que construire les message et il les envoie. A part de très rares exceptions (qui en général résultent de protocoles mal conçus), le lanceur ne doit rien stocker.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    C'est interressant ce que tu me dis.

    Dans mon cas le lanceur ne stock effectivement rien
    Il doit en revanche avoir le lock sur le mutex qui protege la FIFO.

    Comment fais tu pour que le lanceur puisse passer un message a un autre thread sans utiliser de Mutex ?

    Ceci etant meme si tes pistes sont interesantes je ne vois toujours pas comment bloquer le(s) thread(s) de reception pour qu'il(s) ne consomme(nt) pas de CPU si il(s) n'a(ont) rien a faire.

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 156
    Points : 12 269
    Points
    12 269
    Par défaut
    Il doit avoir un Event ET un Mutex.

    Le Mutex pour empêcher la modification concurrentiel de la FIFO et un Event pour faire attendre B.

    Algo de A :
    A construit le message.
    A bloque le Mutex
    A en pile le message
    A débloque le Mutex
    A Signal l'event.
    ....

    Albo de B:
    B attend le signal de l'event
    Quand l'event est signalé B "désignal" l'event (ou event AutoReset)
    B prend le Mutex
    B dépile tous les messages
    B débloque le Mutex
    B attend le signal de l'event

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Merci pour ta reponse

    Ok en supposant que j'ai une seconde FIFO dans B ca pourait simplifer mes affaires.

    Il y a cependant quand meme une faille dans ton algo et c'est cette faille qui est toute la raison d'etre de ce topic.

    Comment gerer le fait que B peut delock le mutex donner la main a A.
    A lock le mutex empile le message, delock le mutex et signal l'event avant de finalement redonner la main a B.

    On est donc bien d'accord pour dire que peut B se retrouver a attendre un event alors qu'il a un message en attente ?

    Et la c'est le drame :p

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 156
    Points : 12 269
    Points
    12 269
    Par défaut
    Ok en supposant que j'ai une seconde FIFO dans B ca pourait simplifer mes affaires.
    Pourquoi? La FIFO partagée suffit.
    Comment gerer le fait que B peut delock le mutex donner la main a A.
    A lock le mutex empile le message, delock le mutex et signal l'event avant de finalement redonner la main a B.

    On est donc bien d'accord pour dire que peut B se retrouver a attendre un event alors qu'il a un message en attente ?
    NON

    B débloque le Mutex et est déchargé du CPU, OK.

    A fait son petit bonhomme de chemin, donc signal l'event. L'event est donc à l'état signalé.

    Quand B revient dans le CPU, il attend sur l'event mais comme il est signalé (l'évent), B peut reprendre sont petit bonhomme de chemin en "désignalant" l'event etc...

  11. #11
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Pour faire simple :

    B, avant de s'endormir sur sa condition variable, prends le mutex, vérifie qu'il n'y a rien à consommer, libère le mutex et s'endort. S'il y a quelque chose à consommer, B le consomme, libère le mutex et le traite comme s'il venait d'être réveillé.

    Sinon, l'intérêt d'un thread séparé pour la file de messages, c'est s'il y a plusieurs consommateurs. Si tu n'as qu'un consommateur, elle peut être intégré à celui-ci.

    bacelar> ça dépend de la méthode utilisée pour signaler l'event. Typiquement, avec une condition variable, si tu n'es pas en wait lorsque le wake survient, l'évènement est perdu.

  12. #12
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Ce que vous appelez ici mutex, pour moi ce n'est qu'un lock. Pour moi, un mutex est un mécanisme qui gère un lock, ici on a juste besoin du lock (un booleen qui dit si l'on peut accéder à la FIFO). Mais bon, c'est juste une question de vocabulaire, je fais cette remarque juste pour qu'on se comprenne.

    A vérifier, mais il me semble que lorsque la FIFO contient des pointeurs (ce qui est souvent le cas lorsqu'on souhaite avoir de la polymorphie sur les messages) on peut se passer de lock, car la copie de pointeur est atomique.

    En revanche, je ne comprends pas l'utilité de la signalisation d'événement ici. En général ce que l'on fait, c'est que le récepteur (qu'il ait un thread ou deux), a une boucle de lecture avec un sleep (dont la durée doit être paramétrable facilement, pour les réglages d'utilisation), et si la FIFO n'est pas vide, alors il fait un pop et gère l'évévenement. Si la FIFO est vide, il ne fait rien.

    Le plus simple est souvent le moins compliqué

  13. #13
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    A vérifier, mais il me semble que lorsque la FIFO contient des pointeurs (ce qui est souvent le cas lorsqu'on souhaite avoir de la polymorphie sur les messages) on peut se passer de lock, car la copie de pointeur est atomique.
    Pas sûr, ça dépend du modèle mémoire je pense. C'est probablement faux au moins sur certaines architectures SMP.

    En revanche, je ne comprends pas l'utilité de la signalisation d'événement ici. En général ce que l'on fait, c'est que le récepteur (qu'il ait un thread ou deux), a une boucle de lecture avec un sleep (dont la durée doit être paramétrable facilement, pour les réglages d'utilisation), et si la FIFO n'est pas vide, alors il fait un pop et gère l'évévenement. Si la FIFO est vide, il ne fait rien.
    Parce que le sleep, c'est très mal et à bannir .Surtout si tu as besoin de réactivité., ou d'autonomie (sleep empêche le processeur de s'endormir, puisqu'il est réveillé régulièrement).

  14. #14
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Parce que le sleep, c'est très mal et à bannir .Surtout si tu as besoin de réactivité., ou d'autonomie (sleep empêche le processeur de s'endormir, puisqu'il est réveillé régulièrement).
    Ha ok. Il y a donc quelque chose que je n'ai pas compris. Je pensais qu'en fait, lorsqu'un receveur est en mode "attente d'un signal", il ne fait rien de plus que ce que j'ai dit, c'est à dire une boucle avec un sleep. Ce n'est donc pas comme ça que ça marche?

  15. #15
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    Non, c'est la différence entre attente active et passive. Un thread dans un sleep ne fait rien, mais il réveille le cpu quand le sleep est fini, ce qui fait qu'il consomme un peu de CPU (pour s'en convaincre, il suffit de diminuer la valeur du sleep).

    Un thread bloqué dans une condition variable ne fait vraiment absolument rien, et n'empêche pas le CPU de se mettre en sommeil. On doit pouvoir retrouver des articles sortis par intel sur comment faire des applications peu énergivores qui expliquent cela plus en détail, notamment les mécanismes sous-jacent dans le cpu.

  16. #16
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Ok merci pour vos reactions

    @bacelar
    Effectivement si tu suppose etre exclusivement sous windows, tu peux utiliser "CreateEvent" de la Win API et dance ce cas pas de souci elle reste signale meme si B ne l'attend pas !
    Mais je crois pas pouvoir faire ca avec des conditionnals varriables. Et ma connaissance il n'y a pas d'equivalent linux au "CreateEvent" de Windows.
    Peut etre les semaphores, mais j'ai trop cherche de ce cote mais j'ai un souvenir des semaphores Linux comme etant de la grosse merde...

    @white_tentacle
    Tu as effectivement compris mon probleme. Je viens de terminer un autre projet avec attente active des threads (cad avec un sleep) et je me souviens avoir eu des perfs vraiment mauvaises !
    Je ne veux donc maintenant faire de la l'attente passive et bannir definitivement le sleep de mes synchronisations .

    @r0d
    Oui quand je parle de Mutex je parle juste de mecanisme de lock
    Sinon a ma connaissance la seule Queue thread safe ne necessitant pas de mutex est celle inclu dans Intel TBB. Mais je n'a jamais eu l'occasion de m'en servir.
    Pour ce qui est des conteneurs STL j'ai lu qu'ils etaient threads safes en lecture mais pas en ecriture (a confirmer) !

    Pour en revenir a mon souci que semblez maintenant avoir compris :p
    Vous n'avez pas une idee pour eviter que B reste bloque dans la condition ?
    L'ideale serait quand meme de trouver un equivalent Linux a CreateEvent ...

    Sinon je suis tombe sur cette excellente page :
    http://www.ibm.com/developerworks/li...-ipc2lin2.html

    Il y a dans la section "Table 3. Event objects mapping" quelques fonctions que je ne connais pas je vais regarder.

    Encore merci.

  17. #17
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    B, avant de s'endormir sur sa condition variable, prends le mutex, vérifie qu'il n'y a rien à consommer, libère le mutex et s'endort. S'il y a quelque chose à consommer, B le consomme, libère le mutex et le traite comme s'il venait d'être réveillé.
    Qu'est-ce qui te déplaît là-dedans ? Il me semble que ça répond à ton problème, non ? .

    Ce n'est pas un problème de perdre des évènement de réveil parce qu'on est déjà réveillé, c'est un problème de s'endormir alors que l'on a quelque chose à consommer.

  18. #18
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Ce n'est pas un problème de perdre des évènement de réveil parce qu'on est déjà réveillé, c'est un problème de s'endormir alors que l'on a quelque chose à consommer.
    Ouais j'ai mal construit ma phrase :p
    C'est ce que je voulais dire.
    Si B s'endort alors qu'il y quelquechose a faire il faudra attendre le reveil suivant pour que B traite les deux messages. Et la c'est la merde ...

    As tu deja trouve une solution a ce probleme ?

  19. #19
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    As tu deja trouve une solution a ce probleme ?
    Je vais finir par croire que tu ne lis pas mes messages

    B, avant de s'endormir sur sa condition variable, prends le mutex, vérifie qu'il n'y a rien à consommer, libère le mutex et s'endort. S'il y a quelque chose à consommer, B le consomme, libère le mutex et le traite comme s'il venait d'être réveillé.

  20. #20
    Membre du Club
    Profil pro
    Inscrit en
    Août 2008
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 56
    Points : 44
    Points
    44
    Par défaut
    Oui mais entre le moment ou B libere le mutex et qu'il s'endort ... A peut passer et rajouter un message. B s'endormira alors sans avoir consome le message de A.

    Enfin je suppose :p

    Tu confirme ?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 13
    Dernier message: 11/06/2015, 15h51
  2. [WD17] Synchronisation de threads avec signaux, comportement bizarre
    Par droliprane dans le forum WinDev
    Réponses: 7
    Dernier message: 08/10/2014, 18h57
  3. Synchronisation des threads avec deux sémpahores
    Par pupucette dans le forum C++
    Réponses: 0
    Dernier message: 27/01/2013, 22h17
  4. Synchronisation thread avec boolean
    Par the_ionic dans le forum Débuter avec Java
    Réponses: 4
    Dernier message: 01/09/2008, 15h25
  5. [POSIX][SIGNAL] envoyer un signal a thread avec sigqueue
    Par Mokhtar BEN MESSAOUD dans le forum POSIX
    Réponses: 3
    Dernier message: 09/02/2006, 18h07

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