C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Thread et condition (pas taper)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Bruno CAUSSE
Guest





PostPosted: Mon Mar 20, 2006 5:06 pm    Post subject: Thread et condition (pas taper) Reply with quote



Bonsoir,

Je sais que le groupe n'est pas le plus adapté (et encore), mais vous etes
"sympas" compétents et francophones.

Je me sers d'une condition pour faire une "sorte" de sémaphore.

class RXEngine {
..../...
POSIXThread condition;
..../...

};

appelé par le thread "ordonnanceur" pour (re)donner la priorité au thread
"traitement"

//sans commentaire
void RXEngine::is_priority() {

mutex_priority.lock();
bool _priority = priority;
mutex_priority.unlock();

return _priority;
}

appelé par le thread "ordonnanceur" pour donner la priorité au thread
"traitement"

void RXEngine::set_priority() {

mutex_priority.lock();
if(!priority) {
priority = true;
condition.signal();
}
mutex_priority.unlock();
}

appelé par le thread "ordonnanceur" pour retirer la priorité au thread
"traitement"

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Pendant le traitement ce code est évalué en "boucle"


.../...
if(!isPriority()) {
timer.wait();
condition.wait();
timer.restart();
}
.../...

Ce code me donne satisfaction (enfin presque sinon il n'y aurai pas de
question)

A la première utilisation mon thread traitement ne s'arrête pas, il faut
attendre le deuxième passage. Apres ça baigne.

Que se passe t'il?

Comment régler cela?
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 10:06 am    Post subject: Re: Thread et condition (pas taper) Reply with quote



dans l'article 1142933640.186633.289470 (AT) u72g2000cwu (DOT) googlegroups.com, kanze
à kanze@gabi-soft.fr a écrit le 21/03/06 10:34 :

Quote:
Deux choses à vérifier. D'abord, que le pthread_cond_t est bien
initialisé AVANT le premier appel à pthread_cond_wait, et
deuxièmement, que tu detiens toujours le mutex chaque fois que
tu appelles pthread_cond_wait.

Merci pour ta réponse :-)

Effectivement après plusieurs lectures j'ai entouré :

condition.lock_mutex();
condition.signal();
condition.unlock_mutex();

Et

condition.lock_mutex();
condition.wait();
condition.unlock_mutex();

Quote:
C'est quoi, POSIXThread. Est-ce qu'il s'agit ici d'un wrapper
pour un pthread_cond_t, ou... ?

Oui, j'utilise ce truc très simple trouvé sur le net :

http://www.partow.net/programming/posixsynchwrapper/index.html

Plutôt que Boost ou Ace qui m'effraies encore.

Quote:
Et il n'y a pas de groupe Posix francophone où les gens sont
aussi sympas et compétents ?

Oui... Mais ou ????

Quote:
Appeler pthread_cond_wait sans avoir contrôle du mutex donne un
comportement indéfini, selon la norme Posix.

C'est énervent un comportement indéfini qui fonctionne bien :-)


Merci bcq
--
Bruno
Back to top
kanze
Guest





PostPosted: Tue Mar 21, 2006 10:06 am    Post subject: Re: Thread et condition (pas taper) Reply with quote



Bruno CAUSSE wrote:

Quote:
Je sais que le groupe n'est pas le plus adapté (et encore),
mais vous etes "sympas" compétents et francophones.

Et il n'y a pas de groupe Posix francophone où les gens sont
aussi sympas et compétents ?

Quote:
Je me sers d'une condition pour faire une "sorte" de sémaphore.

class RXEngine {
.../...
POSIXThread condition;

C'est quoi, POSIXThread. Est-ce qu'il s'agit ici d'un wrapper
pour un pthread_cond_t, ou... ?

Quote:
.../...

};

appelé par le thread "ordonnanceur" pour (re)donner la priorité au thread
"traitement"

//sans commentaire
void RXEngine::is_priority() {

mutex_priority.lock();
bool _priority = priority;
mutex_priority.unlock();

return _priority;
}

appelé par le thread "ordonnanceur" pour donner la priorité au thread
"traitement"

void RXEngine::set_priority() {

mutex_priority.lock();
if(!priority) {
priority = true;
condition.signal();
}
mutex_priority.unlock();
}

appelé par le thread "ordonnanceur" pour retirer la priorité
au thread "traitement"

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();
}

Pendant le traitement ce code est évalué en "boucle"

.../...
if(!isPriority()) {
timer.wait();
condition.wait();
timer.restart();
}
.../...

Si condition est un pthread_cond_t et mutex_priority est un
pthread_mutex_t, et les fonctions membre correspondent aux
requêtes Posix des mêmes noms, c'est incorrect. On doit être en
possession du mutex lors de l'appel de pthread_cond_wait. Donc,
on gros, ce qu'il faut ici, c'est :

mutex_priority.lock() ;
if ( ! priority ) {
condition.wait() ;
}
mutex_priority.unlock() ;

Appeler pthread_cond_wait sans avoir contrôle du mutex donne un
comportement indéfini, selon la norme Posix.

Quote:
Ce code me donne satisfaction (enfin presque sinon il n'y
aurai pas de question)

A la première utilisation mon thread traitement ne s'arrête
pas, il faut attendre le deuxième passage. Apres ça baigne.

Que se passe t'il?

Comment régler cela?

Deux choses à vérifier. D'abord, que le pthread_cond_t est bien
initialisé AVANT le premier appel à pthread_cond_wait, et
deuxièmement, que tu detiens toujours le mutex chaque fois que
tu appelles pthread_cond_wait.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Tue Mar 21, 2006 4:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

Bruno CAUSSE wrote:
Quote:
dans l'article
1142933640.186633.289470 (AT) u72g2000cwu (DOT) googlegroups.com, kanze à
kanze@gabi-soft.fr a écrit le 21/03/06 10:34 :

Deux choses à vérifier. D'abord, que le pthread_cond_t est
bien initialisé AVANT le premier appel à pthread_cond_wait,
et deuxièmement, que tu detiens toujours le mutex chaque
fois que tu appelles pthread_cond_wait.

Effectivement après plusieurs lectures j'ai entouré :

condition.lock_mutex();
condition.signal();
condition.unlock_mutex();

Et

condition.lock_mutex();
condition.wait();
condition.unlock_mutex();

Attention ! Normalement, il faut tester la variable de contrôle
et entrer dans wait sans lacher le mutex entre temps. Sinon, tu
as une possibilité d'une race (« race condition », je ne suis
pas sûr de la traduction française correcte) :

Thread A Thread B

teste variable,
le trouve fausse...

prend le main, met la
variable à vrai, puis fait
signal()

entre dans le wait...

Pour thread B, thread A a été activé. Thread A, en revanche,
attend toujours l'activation. (Dans beaucoup de cas, thread B
finira par attendre une réponse de thread A, pour savoir si la
requête s'est bien passée. Après le scénario ci-dessus, il
risque d'attendre longtemps.) Il ne faut pas que le thread A
puisse être interrompu entre le test de la variable et l'entrée
dans le wait.

Je t'avais indiqué l'idiome consacré. Il ne faut s'en écarter
que dans des cas très spéciax, et s'en écarter comporte de
grandes risques.

À titre indicatif, je t'offre du code de l'implémentation Unix
de ma AbstractMessageQueue:

void
AbstractMessageQueue::send(
void* message )
{
TrivialMutexLocker lock( myImpl->mutex ) ;
myImpl->queue.push_back( message ) ;
pthread_cond_signal( &myImpl->cond ) ;
}

void*
AbstractMessageQueue::poll()
{
void* result = NULL ;
TrivialMutexLocker lock( myImpl->mutex ) ;
if ( ! myImpl->queue.empty() ) {
result = myImpl->queue.front() ;
myImpl->queue.pop_front() ;
}
return result ;
}

void*
AbstractMessageQueue::receive()
{
TrivialMutexLocker lock( myImpl->mutex ) ;
while ( myImpl->queue.empty() ) {
pthread_cond_wait( &myImpl->cond, &myImpl->mutex ) ;
}
void* result = myImpl->queue.front() ;
myImpl->queue.pop_front() ;
return result ;
}

void*
AbstractMessageQueue::receive(
time_t timeout )
{
bool isTimedOut = false ;
void* result = NULL ;
timespec absTimeout ;
clock_gettime( CLOCK_REALTIME, &absTimeout ) ;
absTimeout.tv_sec += timeout ;
TrivialMutexLocker lock( myImpl->mutex ) ;
while ( ! isTimedOut && myImpl->queue.empty() ) {
switch ( pthread_cond_timedwait(
&myImpl->cond, &myImpl->mutex, &absTimeout ) )
{
case 0 :
break ;

case ETIMEDOUT :
isTimedOut = true ;
break ;

default :
assert( 0 ) ;
break ;
}
}
if ( ! myImpl->queue.empty() ) {
result = myImpl->queue.front() ;
myImpl->queue.pop_front() ;
}
return result ;
}

(MessageQueue même est un template, qui dérive de
AbstractMessageQueue. Et AbstractMessageQueue utilise l'idiome
du pare-feu de compilation, de façon à ce que le même en-tête
sert à la fois sous Unix et sous Windows -- il n'y a que
l'implémentation qui change. Le queue même, c'est un
std::deque<void*>.

L'attitude vis-à-vis des erreurs possibles est assez cavalière
aussi. Dans un code « production », il en faudrait bien plus.)

Note surtout les durées que le mutex est tenu.

Et je m'excuse auprès des lecteurs habituels pour ce code, qui
est manifestement spécifique à Posix (mais je suis convaincu
qu'il fonctionne aussi sous Linux).

Quote:
C'est quoi, POSIXThread. Est-ce qu'il s'agit ici d'un
wrapper pour un pthread_cond_t, ou... ?

Oui, j'utilise ce truc très simple trouvé sur le net :

http://www.partow.net/programming/posixsynchwrapper/index.html

Plutôt que Boost ou Ace qui m'effraies encore.

Ace m'effraie aussi. D'autant plus qu'il n'a pas marché pour ce
qu'il m'a fallu (un socket UDP), et que j'ai trouvé des erreurs
dans la gestion de thread par ailleurs.

Boost entier peut être un peu effrayant aussi, vue la quantité
de ce qu'il comporte. Si Boost::treads a un défaut, en revanche,
c'est qu'il est trop simple.

Quote:
Et il n'y a pas de groupe Posix francophone où les gens sont
aussi sympas et compétents ?

Oui... Mais ou ????

Il y a bien un groupe fr.comp.os.unix. Chaque fois que je l'ai
fréquenté, j'ai trouvé les gens compétents et sympas. C'est vrai
que la plupart des postings semblent concernaient plutôt le
shell, mais je crois que les questions sur la programmation y
sont acceptables aussi.

Je ne trouve pas d'équivalent francophone à comp.threads. C'est
dommage ; dans les groupes anglophones, c'est bien là où se
trouvent les experts pour ce genre de question.

Quote:
Appeler pthread_cond_wait sans avoir contrôle du mutex donne
un comportement indéfini, selon la norme Posix.

C'est énervent un comportement indéfini qui fonctionne bien Smile

En règle générale, quand il y a un comportement indéfini, le
code fonctionne parfaitement lors de tes tests, pour se mettre
en erreur d'une façon spectaculaire lors de la démo devant le
client important.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 4:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

dans l'article 1142954650.565826.61240 (AT) g10g2000cwb (DOT) googlegroups.com, kanze à
kanze@gabi-soft.fr a écrit le 21/03/06 16:24 :

Quote:
Attention ! Normalement, il faut tester la variable de contrôle
et entrer dans wait sans lacher le mutex entre temps. Sinon, tu
as une possibilité d'une race (« race condition », je ne suis
pas sûr de la traduction française correcte) :

Thread A Thread B

teste variable,
le trouve fausse...

prend le main, met la
variable à vrai, puis fait
signal()

entre dans le wait...

Pour thread B, thread A a été activé. Thread A, en revanche,
attend toujours l'activation. (Dans beaucoup de cas, thread B
finira par attendre une réponse de thread A, pour savoir si la
requête s'est bien passée. Après le scénario ci-dessus, il
risque d'attendre longtemps.) Il ne faut pas que le thread A
puisse être interrompu entre le test de la variable et l'entrée
dans le wait.

Je t'avais indiqué l'idiome consacré. Il ne faut s'en écarter
que dans des cas très spéciax, et s'en écarter comporte de
grandes risques.

mutex_priority : pour la synchronisation de la variable priority
mutex pour la synchronisation des methodes start() et wait()


void RXEngine::set_priority() {

mutex_priority.lock();
if(!priority) {
priority = true;

condition.lock_mutex();
condition.signal();
condition.unlock_mutex
}
mutex_priority.unlock();
}

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Et dans mon traitement :

mutex_priority.lock();
If(! priority) {

timer.wait();

condition.lock_mutex();
condition.wait();
condition.unlock_mutex();

timer.restart();

}
mutex_priority.unlock();

C'est cela?
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 5:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

dans l'article C045E102.17874%envoi (AT) lesSpam (DOT) fr, Bruno CAUSSE à
envoi (AT) lesSpam (DOT) fr a écrit le 21/03/06 16:57 :

Quote:
C'est cela?

Non

Je bloque mon mutex mutex_priority Sad
Back to top
kanze
Guest





PostPosted: Tue Mar 21, 2006 5:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

Bruno CAUSSE wrote:

Quote:
mutex_priority : pour la synchronisation de la variable priority
mutex pour la synchronisation des methodes start() et wait()

Non ! C'est le même mutex qui doit servir pour les deux.

Sans une régarde dans tes classes, c'est difficile d'être sûr,
mais je crois :

void
RXEngine::set_priority()
{
condition.lock_mutex() ;
if ( ! priority ) {
priority = true ;
condition.signal() ;
}
condition.unlock_mutex() ;
}

void
RXEngine::wait()
{
condition.lock_mutex() ;
while ( ! priority ) {
condition.wait() ;
}
condition.unlock_mutex() ;
}

Quote:
void RXEngine::set_priority() {

mutex_priority.lock();
if(!priority) {
priority = true;

condition.lock_mutex();
condition.signal();
condition.unlock_mutex
}
mutex_priority.unlock();

Il faut que priority soit modifié sous le mutex de la condition.
Sinon, la modification et le reveil des processus en attente
n'est pas atomique, ce qui mène à la condition de race dont j'ai
parlé.

Quote:
}

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Et ici, je ne vois pas du tout où tu attends la condition.

Quote:
Et dans mon traitement :

mutex_priority.lock();
If(! priority) {

timer.wait();

condition.lock_mutex();
condition.wait();
condition.unlock_mutex();

timer.restart();

}
mutex_priority.unlock();

C'est cela?

Non. Tu t'obstines à vouloir séparer deux opérations qui ne
peuvent pas être séparées. La gestion de la condition et les
accès à la variable associée sont indissociable. La variable, la
condition et le mutex forment un tout. En pseudo-code :

set()
{
lock mutex ;
modifier variable ;
signal ou broadcast sur la condition.
unlock mutex ;
}

wait()
{
lock mutex ;
while ( ! variable modifiée ) {
wait sur la condition ;
}
si nécessaire, modifier la variable.
unlock mutex ;
}

Note bien que la variable fait aussi partie du triplet. On ne
l'utilise que pour ça, et on ne s'amuse pas à la modifier
autrement.

Dans le code que j'ai posté, la « variable » était un
std::deque, et les modifications en étaient des appels à
push_back et pop_front -- le test était is ! empty. Si tout ce
que tu veux, c'est une simple sémaphore binaire, un bool suffit,
avec = true et = false comme modifications. (Et si c'est une
simple sémaphore binaire, j'appellerais les fonctions get() et
free().)

En plus, je ne comprends pas la rôle du timer. Si le but est de
mettre un time-out, il existe un appel pthread_cond_timedwait
qui fait l'affaire.

Aussi : si les classes de wrapper dont tu te sers n'offre pas la
possibilité de faire un scoped_lock, ou quelque chose du genre,
jette-les. Sinon, le moindre truc qui foire, et tu risques de
bloquer toute l'application.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 5:06 pm    Post subject: Re: Thread et condition (suite) Reply with quote

dans l'article C045E549.1787D%envoi (AT) lesSpam (DOT) fr, Bruno CAUSSE à
envoi (AT) lesSpam (DOT) fr a écrit le 21/03/06 17:15 :

Quote:
J'espere que je ne vous "gonfle" pas trop avec mon probleme.

et meme supprimer mutex_priority qui fait double emploi avec condition.

Je vais y arriver si si.. :-)

void RXEngine::set_priority() {

condition.lock_mutex();
if(!priority) {
priority = true;

condition.signal();
}
condition.unlock_mutex();
}

void RXEngine::wait() {

mutex.lock();

condition.lock_mutex();
priority = false;
condition.unlock_mutex();

mutex.unlock();

}

Et dans mon traitement :

condition.lock_mutex();
If(! priority) {

timer.wait();

condition.wait();

timer.restart();

}
condition.unlock_mutex();
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 5:06 pm    Post subject: Re: Thread et condition (suite) Reply with quote

mutex_priority : pour la synchronisation de la variable priority
mutex pour la synchronisation des methodes start() et wait()

//sans commentaire
void RXEngine::is_priority() {

mutex_priority.lock();
bool _priority = priority;
mutex_priority.unlock();

return _priority;
}


void RXEngine::set_priority() {

mutex_priority.lock();
if(!priority) {
priority = true;

condition.lock_mutex();
condition.signal();
condition.unlock_mutex
}
mutex_priority.unlock();
}

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Et dans mon traitement :

condition.lock_mutex();
If(! is_priority()) {

timer.wait();

condition.wait();

timer.restart();

}
condition.unlock_mutex();

J'espere que je ne vous "gonfle" pas trop avec mon probleme.
Back to top
Bruno CAUSSE
Guest





PostPosted: Tue Mar 21, 2006 6:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

dans l'article 1142959397.148181.247350 (AT) i40g2000cwc (DOT) googlegroups.com, kanze
à kanze@gabi-soft.fr a écrit le 21/03/06 17:43 :

Quote:
}

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Et ici, je ne vois pas du tout où tu attends la condition.

Je demande au moteur de s'arreter au prochain passage sur la condition.

Quote:
Non. Tu t'obstines à vouloir séparer deux opérations qui ne
peuvent pas être séparées. La gestion de la condition et les
accès à la variable associée sont indissociable. La variable, la
condition et le mutex forment un tout. En pseudo-code :

Note bien que la variable fait aussi partie du triplet. On ne
l'utilise que pour ça, et on ne s'amuse pas à la modifier
autrement.

je viens de le comprendre je crois.

Quote:
En plus, je ne comprends pas la rôle du timer. Si le but est de
mettre un time-out, il existe un appel pthread_cond_timedwait
qui fait l'affaire.

Je programme un jeu de réflexion (Othello). Mon prog joue, sur un serveur de
jeu, des parties simultanées (2 parties identiques en même temps avec les
couleurs inversées) et synchronisées (les coups sont joués en même temps)

Mon but : après avoir terminé la recherche d'un coup, si l'adversaire n'a
pas encore donné le sien (le prog anticipe le coup suivant et réfléchi sur
le temps adverse). Mon ordinateur étant mono core je ne peux mené qu'une
recherche a la fois. Le prog possede deux moteurs, un par jeu. Les moteurs
fonctionnent donc alternativement. D'ou mes interruptions (wait) de
recherche (moteur A/B) pour lancer (un nouvelle recherche si l'anticipation
est mauvaise) ou poursuivre (si l'anticipation est bonne) une recherche sur
l'autre jeu (moteur B/A).

L'ordonnanceur donne la priorité a un moteur en fonction de la demande du
serveur.

Le timer gère le temps (comme sur une partie d'échec)


Quote:
Aussi : si les classes de wrapper dont tu te sers n'offre pas la
possibilité de faire un scoped_lock, ou quelque chose du genre,
jette-les. Sinon, le moindre truc qui foire, et tu risques de
bloquer toute l'application.

Je travaille avec les thread posix depuis une ou deux semaine seulement.

Encore une fois merci.
Back to top
twxs
Guest





PostPosted: Tue Mar 21, 2006 8:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

kanze wrote:
....
Quote:

Plutôt que Boost ou Ace qui m'effraies encore.

Ace m'effraie aussi. D'autant plus qu'il n'a pas marché pour ce
qu'il m'a fallu (un socket UDP), et que j'ai trouvé des erreurs
dans la gestion de thread par ailleurs.


bonjour,
Dans notre projet, nous avons migré notre bus CORBA vers ACE/TAO
et pour uniformiser le code la gestion des threads de tout nos modules
est également passée à ACE.
Pour l'instant nous n'avons pas rencontré de problème "apparent"
(attendons la prochaine demo devant le client Wink ) mais j'aimerai
connaitre quelles sont les erreurs de gestions auquel vous faites référence.

Nicolas
Back to top
Bruno Causse
Guest





PostPosted: Tue Mar 21, 2006 11:06 pm    Post subject: Re: Thread et condition (pas taper) Reply with quote

kanze <kanze@gabi-soft.fr> wrote:

Quote:
Non ! C'est le même mutex qui doit servir pour les deux.

je pense que c'est le paquetage qui est bizare.

http://www.partow.net/programming/posixsynchwrapper/index.html

#ifndef INCLUDE_POSIXCONDITION_H
#define INCLUDE_POSIXCONDITION_H

#include <pthread.h>
#include <sys/time.h>
#include "Utils.h"
#include "POSIXMutex.h"
#include "POSIXSynchronousException.h"
#include "POSIXSynchronousEvent.h"

class POSIXCondition
{

public:

POSIXCondition();
POSIXCondition(const POSIXCondition& obj);
~POSIXCondition();

void wait();
bool wait(unsigned int ms);
void signal();
void broadcast();

void lock_mutex();
void unlock_mutex();

private:

pthread_cond_t condition;
POSIXMutex mutex;
bool sent_signal;

unsigned int active_waiters;

};

#endif

void POSIXCondition::wait()
{
mutex.lock(); <=====

active_waiters++;

while (!sent_signal)
{
pthread_cond_wait(&condition, &(mutex.getMutex()));
}

active_waiters--;

if (active_waiters == 0)
sent_signal = false;

mutex.unlock(); <=====
};

j'ai suprimé ces 2 lignes partout dans le code de POSIXCondition:
et appliquer tes conseils et c'est ok.

merci
--
Bruno Causse
http://perso.wanadoo.fr/othello
Back to top
kanze
Guest





PostPosted: Wed Mar 22, 2006 9:06 am    Post subject: Re: Thread et condition (pas taper) Reply with quote

Bruno CAUSSE wrote:
Quote:
dans l'article
1142959397.148181.247350 (AT) i40g2000cwc (DOT) googlegroups.com, kanze à
kanze@gabi-soft.fr a écrit le 21/03/06 17:43 :

}

void RXEngine::wait() {

mutex.lock();

mutex_priority.lock();
priority = false;
mutex_priority.unlock();

mutex.unlock();

}

Et ici, je ne vois pas du tout où tu attends la condition.

Je demande au moteur de s'arreter au prochain passage sur la
condition.

Je l'aurais appelé requestWait(), ou quelque chose du genre,
alors. Le mot wait(), tout seul, s'applique prèsque toujours à
la fonction où on attend.

Quote:
Non. Tu t'obstines à vouloir séparer deux opérations qui ne
peuvent pas être séparées. La gestion de la condition et les
accès à la variable associée sont indissociable. La
variable, la condition et le mutex forment un tout. En
pseudo-code :

Note bien que la variable fait aussi partie du triplet. On
ne l'utilise que pour ça, et on ne s'amuse pas à la modifier
autrement.

je viens de le comprendre je crois.

C'est difficile d'expliquer en si peu de place. Si tu lis
l'anglais, je ne peux que te conseiller le Butenhof :
« Programming with POSIX Threads » (Addison-Wesley, ISBN
0-201-63392-2). (Je ne sais pas s'il a été traduit. Beaucoup de
chez Addison-Wesley l'est. Mais la qualité des traductions n'est
pas toujours très bien -- en général, il vaut mieux de
débrouiller avec l'original, si on peut. Et réalistiquement : si
on ne peut pas, il vaut mieux apprendre de le pouvoir. L'anglais
est incontournable si on veut rester à jour.)

Quote:
En plus, je ne comprends pas la rôle du timer. Si le but est
de mettre un time-out, il existe un appel
pthread_cond_timedwait qui fait l'affaire.

Je programme un jeu de réflexion (Othello). Mon prog joue, sur
un serveur de jeu, des parties simultanées (2 parties
identiques en même temps avec les couleurs inversées) et
synchronisées (les coups sont joués en même temps)

Mon but : après avoir terminé la recherche d'un coup, si
l'adversaire n'a pas encore donné le sien (le prog anticipe le
coup suivant et réfléchi sur le temps adverse). Mon ordinateur
étant mono core je ne peux mené qu'une recherche a la fois. Le
prog possede deux moteurs, un par jeu. Les moteurs
fonctionnent donc alternativement. D'ou mes interruptions
(wait) de recherche (moteur A/B) pour lancer (un nouvelle
recherche si l'anticipation est mauvaise) ou poursuivre (si
l'anticipation est bonne) une recherche sur l'autre jeu
(moteur B/A).

Pour confirmer que j'ai bien compris, chaque thread
exécute une boucle un peu comme :

while ( ! gameOver ) {
semaphore.wait() ;
Microtime start = getTime() ;
while ( getTime() < start - turnLength ) {
// Un pas de calcul...
}
semaphore.unblock() ;
pause() ; // Pour être certain que l'autre thread
// ait le temps de prendre le semaphore.
}

Tout ça m'a l'air un peu compliqué. Et peut-être pas
nécessaire : sur la plupart des systèmes, les threads sont
time-slicés par défaut, ce qui veut dire que le système veut
automatiquement donner du temps d'abord à un, ensuite à l'autre.
Si ça ne suffisait pas dans la pratique, je crois que
j'utiliserais deux processus, plutôt que deux threads. Et pour
s'assurer que l'alternance se fait correctement, plutôt que de
compter sur le fait que l'autre prend la main avant que je ne
reviens le démander, j'utiliserait un sémaphore par thread -- en
fait, j'utiliserais deux MessageQueue, parce que c'est du code
que j'ai déjà sous la main, testé, avec un seul message comme
token (ou comme le baton d'un courreur dans un relai). La boucle
deviendrait donc quelque chose comme :

while ( ! gameOver ) {
std::auto_ptr< void > token = myMessageQueue.receive() ;
// boucle avec timer...
otherMessageQueue.send( token ) ;
}

Mais évidemment, ici, le message même est bidon, et on pourrait
facilement le remplacer par un simple booléan. Quelque chose du
genre :

while ( ! gameOver ) {
mySemaphore.wait() ;
mySemaphore.block() ;
// boucle avec timer ...
otherSemaphore.unblock() ;
}

Quote:
L'ordonnanceur donne la priorité a un moteur en fonction de la
demande du serveur.

Le timer gère le temps (comme sur une partie d'échec)

Alors, je ne suis pas sûr d'avoir bien compris. C-à-d qu'on
débloque l'un ou l'autre thread, selon à qui le tour ? Et que
chaque thread a son propre timer, qui ne tourne que quand le
thread est actif ? Il faudrait que j'y reflechisse, mais je
crois qu'il faut un thread pour le timer (avec une priorité plus
élevée que les autres, si possible). Mais la gestion des temps
réels n'est jamais simple. On pourrait imaginer aussi que quand
le temps est épuisé, on cancelle le thread. Mais la cancellation
des threads est vraiment un topic avancé, surtout en C++, où
elle interagit avec les destructeeurs d'une façon qui dépend du
compilateur. (Je ne me rappelle plus qui fait quoi, mais je me
rappelle bien que sous Solaris, Sun CC et g++ se comportent
différemment par rapport à la cancellation.)

Quote:
Aussi : si les classes de wrapper dont tu te sers n'offre
pas la possibilité de faire un scoped_lock, ou quelque chose
du genre, jette-les. Sinon, le moindre truc qui foire, et tu
risques de bloquer toute l'application.

Je travaille avec les thread posix depuis une ou deux semaine
seulement.

Alors, chaque chose dans son temps. Laisse tomber le timer
jusqu'à ce que la reste marche.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Wed Mar 22, 2006 9:06 am    Post subject: Re: Thread et condition (pas taper) Reply with quote

Bruno Causse wrote:
Quote:
kanze <kanze@gabi-soft.fr> wrote:

Non ! C'est le même mutex qui doit servir pour les deux.

je pense que c'est le paquetage qui est bizare.

Je pense que les auteurs n'ont rien compris:-).

Quote:
http://www.partow.net/programming/posixsynchwrapper/index.html

#ifndef INCLUDE_POSIXCONDITION_H
#define INCLUDE_POSIXCONDITION_H

#include <pthread.h
#include <sys/time.h
#include "Utils.h"
#include "POSIXMutex.h"
#include "POSIXSynchronousException.h"
#include "POSIXSynchronousEvent.h"

class POSIXCondition
{
public:

POSIXCondition();
POSIXCondition(const POSIXCondition& obj);
~POSIXCondition();

void wait();
bool wait(unsigned int ms);
void signal();
void broadcast();

void lock_mutex();
void unlock_mutex();

private:
pthread_cond_t condition;
POSIXMutex mutex;
bool sent_signal;

unsigned int active_waiters;
};
#endif

Je veux bien qu'ils associent le condition et le mutex. C'est
même une bonne idée, puisqu'il faut les utiliser ensemble.

J'ai l'impression, en revanche, qu'ils ont emballé la variable
aussi (et je ne vois pas l'intérêt de « active_waiters »).
Supérficiellement, ça pourrait apparaître une bonne idée aussi,
puisqu'il faut l'utiliser avec les autres. Seulement, la raison
Posix ne l'a pas fait, c'est que le type de la variable dépend
de ce qu'on veut faire -- si tu régarde ma MessageQueue, par
exemple, la variable est un std::deque<void*> (et la condition
qu'on garde, c'est ! queue.empty(). Si on emballe aussi la
variable, alors 1) on ne doit pas donner accès au mutex, parce
qu'il ne sert à rien à l'utilisateur, et 2) il ne faut pas
l'appeler « condition », parce qu'il utilise une condition
précise pour implémenter quelque chose de plus haut niveau, et
ne permet pas de condition arbitraire.

Quote:
void POSIXCondition::wait()
{
mutex.lock(); <====
active_waiters++;

while (!sent_signal)
{
pthread_cond_wait(&condition, &(mutex.getMutex()));
}

active_waiters--;

if (active_waiters == 0)
sent_signal = false;

mutex.unlock(); <====> };

C'est en fait une attente sur la condition interne, sent_signal.
Sauf que je ne comprends pas trop l'histoire de active_waiters ;
le signal va rester passant jusqu'à ce que tous les threads en
attente ont été éveillés. Pour que ça puisse même avoir l'air de
marcher, il faut ou bien qu'il n'y a jamais plus d'un thread qui
se met en attente, ou bien qu'on n'utilise que broadcast, et non
signal. Et même alors, ce n'est qu'un air quand il y a plus d'un
thread en attente, parce que même avec broadcast, rien ne
garantit que le premier thread éveillé ne revient pas dans wait
avant que les autres threads ont pris la main.

Quote:
j'ai suprimé ces 2 lignes partout dans le code de
POSIXCondition: et appliquer tes conseils et c'est ok.

Je crois que le mieux serait de supprimer l'utilisation de cette
bibliothèque. Je te conseillerais vivement boost::thread -- ou
même, puisque le but est au moins partiellement pédogogique,
d'implémenter des petits wrappers toi-même : il te faut un
mutex, un scoped_lock, et alors, je te conseillerais des
utilisations déjà d'un niveau plus élevé des conditions, du
genre MessageQueue ou un sémaphore. Des utilisations qui ne
revèlent ni le mutex ni la condition Posix à l'utilisateur.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
kanze
Guest





PostPosted: Wed Mar 22, 2006 10:06 am    Post subject: Re: Thread et condition (pas taper) Reply with quote

twxs wrote:
Quote:
kanze wrote:
...

Plutôt que Boost ou Ace qui m'effraies encore.

Ace m'effraie aussi. D'autant plus qu'il n'a pas marché pour
ce qu'il m'a fallu (un socket UDP), et que j'ai trouvé des
erreurs dans la gestion de thread par ailleurs.

Dans notre projet, nous avons migré notre bus CORBA vers
ACE/TAO et pour uniformiser le code la gestion des threads de
tout nos modules est également passée à ACE.

Pour l'instant nous n'avons pas rencontré de problème
"apparent" (attendons la prochaine demo devant le client Wink )
mais j'aimerai connaitre quelles sont les erreurs de gestions
auquel vous faites référence.

Il y a des accès sans protection à des variables qui peuvent
être modifiées par un autre thread (l'idiome « double checked
locking »). Tant que tu te trouves sur une machine mono-core, ou
sur une machine qui ne fait pas de lectures spéculatives, ça
devait marcher. Aussi, il n'y a modification que lors du premier
accès -- s'il n'y a pas de conflit lors du premier accès, tout
va bien. (Dans la plupart des utilisations, aussi, je crois que
l'erreur ne se manifestera que par une fuite de mémoire, quand
elle se manifeste.)

Ce qui me gène dans tout ça, c'est que l'erreur est connue des
auteurs, et qu'ils choisissent de ne pas le corréger, parce
qu'ils ne savent pas le mettre en évidence sur les machines à
leur disposition. C'est une attitude de base qui me fait
franchement peur -- c'est souvent très difficile à mettre en
évidence des erreurs de thread, mais ce n'est pas pour autant
qu'il faut les ignorer. Alors, du coup, je me démande s'il n'y
en a pas d'autres, qui risque encore plus de se manifester dans
la pratique, dans la vaste majorité du code que je n'ai pas
régardé.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.