Synchronisation de threads en c++

Bonjour,

J’ai un thread qui tourne en boucle et qui mets à jours des variables. Il met à jour soit la variable a[0] soit la variable a[1], a[2] … a[MAX] (mettre à jour toutes les variables en même temps serait beaucoup trop lent). A chaque itération, il ne met à jour que la variable “active” par exemple la a[0] et il fait ça sans arrêt.

J’ai une fonction GetValue(int index) que j’appelle depuis le programme appelant et qui me retourne a[index]. Si la variable active est la a[0] et que je veux lire la variable a[1] je suis dans la mouise car a[1] contient n’importe quoi.

Donc voilà ce que je veux faire:

(En admettant que a[0] est la variable active)

Si je fais GetValue(0), pas de problème, je retourne la valeur a[0].
Si je fais GetValue(1), je veux que GetValue:

  1. Active la variable 1
  2. Attende que mon thread ait effectué une itération et mis à jour la variable 1
  3. Retourne la valeur de a[1] qui maintenant est valide

Et voilà le problème, comment je fais pour que ma fonction GetValue attende que le thread ait fait une itération?

Apparemment il faut utiliser WaitForSingleObject ou quelque chose comme ça mais je ne sais pas sur quel type d’objet je dois attendre. Il faudrait que je crée un objet dans GetValue, que j’attende dessus et que le thread le libère quand il a finit, mais j’en suis pas très sûr.

Je vous remercie d’avance de prêter attention à mon problème.

salut =)

au vu des foncions waitForSingleObject j’imagine que tu developpes sous windows avec la core API…

donc waitForSingleObject ne me parait pas bien adaptee pr l’utilisation que tu veux en faire, car elle ne fait que bloquer le deroulement d’un thread pdt qu’un autre travaille ou doit finir…

deja une chose:
ton thread qui utilise la fontion GetValue et celui qui met a jour cette valeur sont ils differents?
si oui, verifie que ces deux threads ne se genent pas en voulantr acceder a la meme valeur en meme tps tu aurais une belle exception ou un comportment erroné, voire imprevisible.
donc verifie que ton tableau value[] est une zone securisee (c-a-d dont l’acces est regulee par un lock)

tu peux essayer aussi d’approfondir tes explications?
et si possible filer les liens sur les fonctions waitforsingleobject de MSDN (j’ai la flemme :P)

Pour pouvoir aider, j’aimerai bien que tu exprimes le besoin plutôt que de demander une solution toute faite, qui est peut-être complètement aux fraises. Déjà, un thread qui tourne sans arrêt pour mettre à jour une table…mmmm… ça pue :stuck_out_tongue:

Si j’ai bien compris, tu as un asynchronisme entre le thread qui met à jour la table et le thread depuis lequel tu va chercher les infos dans la table, c’est ça ?

  • Pourquoi dois-tu maintenir la table à jour via un polling ? tu ne peux pas être prévenu ?

Si tu veux que GetValue soit synchro avec l’autre thread, il faut que GetValue discute avec le premier thread. cf. CEvent par exemple, mais bon une réponse comme ça à la vache t’en fout à toute les chances d’être mauvaise.

EDIT : si tu n’as pas le temps d’expliquer ou tu ne veux pas, voici quelques mots clés :
CMultiLock
CEvent
PostMessage

Tout d’abord, merci pour vos réponses.

C’est vrai que je n’ai peut-être pas été assez clair…

Déjà je programme avec visual studio .NET 2003 sous Windows, sans les MFC et j’utilise donc le core API Windows.

Oui j’ai deux threads différents, celui qui met à jour la valeur et celui du programme appelant qui appelle GetValue().

J’ai protégé l’accès à mon tableau avec une critical section donc jusque là, il n’y a pas de problèmes.

Berzek:
voici le lien que tu demandes
WaitForSingleObject

Moktar:

Oui Moktar, c’est bien ça.

Le problème c’est que le thread du programme appelant appelle soit la fonction GetValue qui doit être triggée sur le thread qui met à jour la valeur mais le thread du programme appelant peut aussi appeler des fonctions qui ne doivent pas être triggée sur le thread qui met à jour la valeur.

Donc pour résumer mon besoin:
Je veux que ma fonction GetValue() soit bloquante jusqu’à ce que l’autre thread ait finit son itération et ait mis à jour la valeur. Donc si j’appelle GetValue() fréquemment, le thread appelant est triggé sur le thread qui met à jour la valeur.

Edit: Ortho

Mmmmm mouaif…

Bon je donne une piste comme ça à l’arrache :

Ton thread de polling va faire un WaitForMultipleObjects sur une liste d’Event qui aura été créée auparavant. Cette liste d’Event ne servira qu’à synchroniser le producteur (le thread qui rempli la table) et le consommateur (celui qui appelle GetValue) et contiendra autant d’Event qu’il y a d’entrée à ta table.

Le WaitForMultipleObjects devra avoir un timeout de façon à faire son autre boulot (remplissage de la table). En revanche sur l’Event WAIT_OBJECT_0 + n, il va tester si ta value est “active” Si elle l’est hop signalisation à GetValue que la donnée est prête, sinon ben il fait le boulot d’abord et signalisation une fois que la donnée est prête et il se remet en attente.

Oui, je n’ai pas parlé de cette signalisation mentionné ci-dessus. Il s’agit en fait dans le code de GetValue de :

Lever l’Event correspondant à l’entrée du tableau que tu souhaites faire lire et se mettre en attente de la réponse ==> 1 seul Event à attendre qui sera signalé par le thread producteur.

La méthode qui va bien me semble : SignalObjectAndWait

EDIT : j’ai eu une autre idée dans la nuit qui me semble plus élégante mais je ne suis pas sûr que ce soit possible. Je recommence à peine le dev sous Windows :/.
Il suffirait de faire hériter ta méthode décrivant le thread de polling de CWnd, comme ça tu récupères la possibilité de lui envoyer des messages avec des paramètres : Index dans la table et autre chose. Ca me semble plus sioux.

A noter que dans le premier exemple, plus besoin d’exclusion mutuelle puisque le thread de polling joue le rôle de serveur.

Ok, je vais donc essayer tout ça.

Merci pour ton aide Moktar.

Avec les sections critiques, cela devrait fonctionner sans trop de problème.

Conseil : un GetValue qui modifie des valeurs, sémantiquement c’est mal. Le Get il Get point final.

Sinon passe par une solution à base de mutex.

Le thread qui écrit prend le mutex, GetValue fait une attente infinie sur le mutex (Via effectivement la fonction WaitForSingleObject), une fois que le thread d’écriture a fini d’écrire il rend le mutex, et GetValue peut récupérer la valeur…

Il suffit d’appliquer ou non le même mécanisme sur chaque fonction appelante que tu veux protéger ou non.

Cela ne doit pas prendre plus de 5 lignes au total.

Conseil 2 (Je suis dans un bon jour) privilégie une solution simple à débugger. Le multithread si trop complexe peut rapidement devenir une bouse infame à mettre au point. Si par hasard un redesign te permet de te passer du multithread, c’est une piste à étudier (hormis si le multithread est une contrainte lié à l’achitecture ou à la durée des traitements)

Je suis effectivement obligé de faire du multithread (car en fait ma valeur retournée par GetValue() est issue d’un traitement d’image et je veux que le programme continue à filmer même si je fais pas de GetValue() et en plus je fais pas tout le temps des GetValue(), enfin bref).

Je suis obligé de faire comme ça et c’est pas vraiment une modification, c’est plutôt une activation. (oui bon t’as raison c’est pareil, c’est sâle).

Tant qu’a faire je vais plutôt essayer avec des sections critiques. Mon thread principal lock tout le temps, puis unlock, relock à chaque itération et du coup ma fonction GetValue() s’execute juste à ce moment.