Je viens de rencontrer un problème bizarre et j'aimerais savoir si
c'est moi qui n'aie pas tout compris aux classes C++ ou si c'est mon
compilo qui a un problème.
Considérons une classe gérant un port quelconque (dans mon programme
un port série mais ce n'est pas important) dans laquelle est définie
une fonction purement virtuelle définie dans une classe héritée de
la première.
Le constructeur de la classe mère lance deux threads utilisant ma
fonction purement virtuelle :
- un pour la lecture sur ce port ;
- un second pour l'écriture sur ce port.
Là où ça se corse, c'est que mon constructeur est appelé depuis une
autre classe créant un thread.
Avec un petit dessin, cela donne :
main->classe driver
+-> thread spécifique créé dans le constructeur de driver
+-> constructeur serialPort
+-> thread lecture
+-> thread écriture
Le souci arrive lors de l'appel des destructeurs. Je détruis driver
(avec un delete, l'objet étant créé par un new) qui doit, il me
semble, appeler dans l'ordre inverse de création les destructeurs
associés. Ça se passe bien, sauf que j'ai un énorme problème avec ma
fonction virtuelle.
Mon destructeur fautif (celui de la classe implantant cette fameuse
fonction virtuelle) arrête le thread qui utilise cette fonction et
attend la fin de ce thread (avec un pthread_join()). L'ennui est
qu'à la fin du thread en question, j'utilise la fonction virtuelle
en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça
donne :
fonction()
{
while(_requete_arret == 0)
{
lecture_port();
fonction_virtuelle(); // vaut NULL dès l'appel à ~classe
}
}
Il m'aurait semblé logique que la fonction virtuelle soit
déréférencée en sortie du destructeur et non à l'entrée. Alors,
est-ce moi qui aie encore compris un truc de travers ?
Merci de vos lumières,
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Pascal J. Bourguignon
JKB writes:
Mon destructeur fautif (celui de la classe implantant cette fameuse fonction virtuelle) arrête le thread qui utilise cette fonction et attend la fin de ce thread (avec un pthread_join()). L'ennui est qu'à la fin du thread en question, j'utilise la fonction virtuelle en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça donne :
fonction() { while(_requete_arret == 0) { lecture_port(); fonction_virtuelle(); // vaut NULL dès l'appel à ~classe } }
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée. Alors, est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions virtuelles sur l'objet qu'on est en train de supprimer dans le destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre threads, car la simple variable _requete_arret ne peut pas empêcher l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être mis à -1 après le test du while). Il faut utiliser ici un mutex, afin que le destructeur ne tue pas le thread, tant qu'il est encore dans la boucle while.
-- __Pascal Bourguignon__ http://www.informatimago.com/ A bad day in () is better than a good day in {}.
JKB <jkb@koenigsberg.invalid> writes:
Mon destructeur fautif (celui de la classe implantant cette fameuse
fonction virtuelle) arrête le thread qui utilise cette fonction et
attend la fin de ce thread (avec un pthread_join()). L'ennui est
qu'à la fin du thread en question, j'utilise la fonction virtuelle
en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça
donne :
fonction()
{
while(_requete_arret == 0)
{
lecture_port();
fonction_virtuelle(); // vaut NULL dès l'appel à ~classe
}
}
Il m'aurait semblé logique que la fonction virtuelle soit
déréférencée en sortie du destructeur et non à l'entrée. Alors,
est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions
virtuelles sur l'objet qu'on est en train de supprimer dans le
destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre
threads, car la simple variable _requete_arret ne peut pas empêcher
l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être
mis à -1 après le test du while). Il faut utiliser ici un mutex, afin
que le destructeur ne tue pas le thread, tant qu'il est encore dans la
boucle while.
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
Mon destructeur fautif (celui de la classe implantant cette fameuse fonction virtuelle) arrête le thread qui utilise cette fonction et attend la fin de ce thread (avec un pthread_join()). L'ennui est qu'à la fin du thread en question, j'utilise la fonction virtuelle en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça donne :
fonction() { while(_requete_arret == 0) { lecture_port(); fonction_virtuelle(); // vaut NULL dès l'appel à ~classe } }
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée. Alors, est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions virtuelles sur l'objet qu'on est en train de supprimer dans le destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre threads, car la simple variable _requete_arret ne peut pas empêcher l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être mis à -1 après le test du while). Il faut utiliser ici un mutex, afin que le destructeur ne tue pas le thread, tant qu'il est encore dans la boucle while.
-- __Pascal Bourguignon__ http://www.informatimago.com/ A bad day in () is better than a good day in {}.
JKB
Le Fri, 28 Oct 2011 15:48:53 +0200, Pascal J. Bourguignon écrivait :
JKB writes:
Mon destructeur fautif (celui de la classe implantant cette fameuse fonction virtuelle) arrête le thread qui utilise cette fonction et attend la fin de ce thread (avec un pthread_join()). L'ennui est qu'à la fin du thread en question, j'utilise la fonction virtuelle en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça donne :
fonction() { while(_requete_arret == 0) { lecture_port(); fonction_virtuelle(); // vaut NULL dès l'appel à ~classe } }
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée. Alors, est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions virtuelles sur l'objet qu'on est en train de supprimer dans le destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre threads, car la simple variable _requete_arret ne peut pas empêcher l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être mis à -1 après le test du while). Il faut utiliser ici un mutex, afin que le destructeur ne tue pas le thread, tant qu'il est encore dans la boucle while.
C'est du pseudo-code. Le mécanisme est un peu plus compliqué et prend naturellement en compte ce que tu m'indiques. C'est pour cela que le pthread_kill() utilise un SIGUSR1. Dans mon code réel, cela force le passage par le while().
Merci pour la réponse.
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Le Fri, 28 Oct 2011 15:48:53 +0200,
Pascal J. Bourguignon <pjb@informatimago.com> écrivait :
JKB <jkb@koenigsberg.invalid> writes:
Mon destructeur fautif (celui de la classe implantant cette fameuse
fonction virtuelle) arrête le thread qui utilise cette fonction et
attend la fin de ce thread (avec un pthread_join()). L'ennui est
qu'à la fin du thread en question, j'utilise la fonction virtuelle
en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça
donne :
fonction()
{
while(_requete_arret == 0)
{
lecture_port();
fonction_virtuelle(); // vaut NULL dès l'appel à ~classe
}
}
Il m'aurait semblé logique que la fonction virtuelle soit
déréférencée en sortie du destructeur et non à l'entrée. Alors,
est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions
virtuelles sur l'objet qu'on est en train de supprimer dans le
destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre
threads, car la simple variable _requete_arret ne peut pas empêcher
l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être
mis à -1 après le test du while). Il faut utiliser ici un mutex, afin
que le destructeur ne tue pas le thread, tant qu'il est encore dans la
boucle while.
C'est du pseudo-code. Le mécanisme est un peu plus compliqué et
prend naturellement en compte ce que tu m'indiques. C'est pour cela
que le pthread_kill() utilise un SIGUSR1. Dans mon code réel, cela
force le passage par le while().
Merci pour la réponse.
Cordialement,
JKB
--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Le Fri, 28 Oct 2011 15:48:53 +0200, Pascal J. Bourguignon écrivait :
JKB writes:
Mon destructeur fautif (celui de la classe implantant cette fameuse fonction virtuelle) arrête le thread qui utilise cette fonction et attend la fin de ce thread (avec un pthread_join()). L'ennui est qu'à la fin du thread en question, j'utilise la fonction virtuelle en question et qu'elle pointe déjà sur NULL. En pseudo-code, ça donne :
fonction() { while(_requete_arret == 0) { lecture_port(); fonction_virtuelle(); // vaut NULL dès l'appel à ~classe } }
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée. Alors, est-ce moi qui aie encore compris un truc de travers ?
Si je me souviens bien, en effet, il ne faut pas appeler de fonctions virtuelles sur l'objet qu'on est en train de supprimer dans le destructeur.
D'autre part, tu as là clairement un problème de synchronisation entre threads, car la simple variable _requete_arret ne peut pas empêcher l'appel à lecture_port et fonction_virtuelle (_requete_arret peut être mis à -1 après le test du while). Il faut utiliser ici un mutex, afin que le destructeur ne tue pas le thread, tant qu'il est encore dans la boucle while.
C'est du pseudo-code. Le mécanisme est un peu plus compliqué et prend naturellement en compte ce que tu m'indiques. C'est pour cela que le pthread_kill() utilise un SIGUSR1. Dans mon code réel, cela force le passage par le while().
Merci pour la réponse.
Cordialement,
JKB
-- Si votre demande me parvient sur carte perforée, je titiouaillerai très volontiers une réponse... => http://grincheux.de-charybde-en-scylla.fr
Fabien LE LEZ
On Fri, 28 Oct 2011 13:34:20 +0000 (UTC), JKB :
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée.
Je ne sais pas trop ce que tu appelles "déréférencée".
Dans un constructeur et un destructeur, le type dynamique est le même que le type statique.
En fait, quand le destructeur de la classe de base est appelé, l'objet n'a déjà plus la classe "dérivée". De même, quand le constructeur de la classe de base est appelée, l'objet n'a pas encore la classe "dérivée".
On Fri, 28 Oct 2011 13:34:20 +0000 (UTC), JKB
<jkb@koenigsberg.invalid>:
Il m'aurait semblé logique que la fonction virtuelle soit
déréférencée en sortie du destructeur et non à l'entrée.
Je ne sais pas trop ce que tu appelles "déréférencée".
Dans un constructeur et un destructeur, le type dynamique est le même
que le type statique.
En fait, quand le destructeur de la classe de base est appelé, l'objet
n'a déjà plus la classe "dérivée". De même, quand le constructeur de
la classe de base est appelée, l'objet n'a pas encore la classe
"dérivée".
Il m'aurait semblé logique que la fonction virtuelle soit déréférencée en sortie du destructeur et non à l'entrée.
Je ne sais pas trop ce que tu appelles "déréférencée".
Dans un constructeur et un destructeur, le type dynamique est le même que le type statique.
En fait, quand le destructeur de la classe de base est appelé, l'objet n'a déjà plus la classe "dérivée". De même, quand le constructeur de la classe de base est appelée, l'objet n'a pas encore la classe "dérivée".