"Jean-Marc Bourguet" wrote in message news: > "Eric Bart" writes:
Après un erase, l'itérateur aura une valeur différente. Pour détecter un erase, peut-on de faire une comparaison entre l'itérateur en référence et l'itérateur en recopie. S'il diffère, il y a eu un erase ... non ?
Si j'ai bien compris, non.
même si je fais
Un iterateur ne sait pas s'il est valide ou non.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
"Jean-Marc Bourguet" <jm@bourguet.org> wrote in message
news:pxbfz5law8g.fsf@news.bourguet.org... > "Eric Bart"
<eb-adm@eric-bart.pasdepubmerci.net> writes:
Après un erase, l'itérateur aura une valeur différente. Pour
détecter un erase, peut-on de faire une comparaison entre
l'itérateur en référence et l'itérateur en recopie. S'il diffère, il
y a eu un erase ... non ?
Si j'ai bien compris, non.
même si je fais
Un iterateur ne sait pas s'il est valide ou non.
A+
--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
"Jean-Marc Bourguet" wrote in message news: > "Eric Bart" writes:
Après un erase, l'itérateur aura une valeur différente. Pour détecter un erase, peut-on de faire une comparaison entre l'itérateur en référence et l'itérateur en recopie. S'il diffère, il y a eu un erase ... non ?
Si j'ai bien compris, non.
même si je fais
Un iterateur ne sait pas s'il est valide ou non.
A+
-- Jean-Marc FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html Site de usenet-fr: http://www.usenet-fr.news.eu.org
Loïc Joly
Fabien LE LEZ wrote:
On Tue, 14 Sep 2004 13:27:20 +0200, "Eric Bart" :
j'aimerais faire un erase de cet itérateur.
Tu t'aventures là dans les méandres de la programmation multithread -- et en profites pour sortir du cadre du présent forum, mais je me permettrai une petite digression.
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle. Il faut bien entendu que le "petit trafic" en question soit le plus court possible, car le mutex peut avoir pour effet de bloquer les autres threads.
Il y a une alternative, pour certains types de données, on peut effectuer des opérations atomiques, du genre décrémenter et regarder si le résultat est nul, sans pouvoir être intérrompu. Ces opérations permettent a priori de programmer du code plus rapide qu'avec des mutex.
-- Loïc
Fabien LE LEZ wrote:
On Tue, 14 Sep 2004 13:27:20 +0200, "Eric Bart"
<eb-adm@eric-bart.pasdepubmerci.net>:
j'aimerais faire un erase de cet itérateur.
Tu t'aventures là dans les méandres de la programmation multithread --
et en profites pour sortir du cadre du présent forum, mais je me
permettrai une petite digression.
En programmation multithread, si deux threads peuvent accéder en même
temps au même objet, dont au moins un en écriture, il faut mettre un
mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux
autres threads d'y accéder, y fait son petit trafic, et relâche le
contrôle. Il faut bien entendu que le "petit trafic" en question soit
le plus court possible, car le mutex peut avoir pour effet de bloquer
les autres threads.
Il y a une alternative, pour certains types de données, on peut
effectuer des opérations atomiques, du genre décrémenter et regarder si
le résultat est nul, sans pouvoir être intérrompu. Ces opérations
permettent a priori de programmer du code plus rapide qu'avec des mutex.
Tu t'aventures là dans les méandres de la programmation multithread -- et en profites pour sortir du cadre du présent forum, mais je me permettrai une petite digression.
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle. Il faut bien entendu que le "petit trafic" en question soit le plus court possible, car le mutex peut avoir pour effet de bloquer les autres threads.
Il y a une alternative, pour certains types de données, on peut effectuer des opérations atomiques, du genre décrémenter et regarder si le résultat est nul, sans pouvoir être intérrompu. Ces opérations permettent a priori de programmer du code plus rapide qu'avec des mutex.
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui peuvent en faire joujou, ce qui limite la nécessité des locks.
La méthode générale pour faire ça est :
void * axraAnnounceCid(void * ptr) { T &t= *reinterpret_cast<T*>(ptr);
(où T est list<machin>::iterator )
mais note que l'objet d'origine doit toujours exister (sinon ton "void*" ne pointe sur rien).
Il y a un problème de durée de vie dans tous les cas. La solution « générale » consiste à allouer un struct dynamiquement, et d'y mettre tout ce que on veut passer au thread. En phase de démarrage, le thread copie alors les information de la struct aux endroits où il veut bien l'avoir, et libère le struct.
Comme toute solution générale, elle peut être un peu lourde pour les cas simples. Mais il ne faut jamais perdre de vue qu'on ne sait pas quand le thread va réelement démarrer, par rapport au thread qui appelle pthread_create. Il ne faut donc jamais que quelque chose dont on a passé un pointeur ou une référence cesse de vivre avant qu'on a eu une indication réele du thread qu'il n'en a plus besoin.
Si tu veux copier l'objet, je serais d'avis de le faire explicitement :
void * axraAnnounceCid(void * ptr) { T &t_reference= *reinterpret_cast<T*>(ptr); T copie_de_lobjet (t_reference);
Où est la différence par rapport à :
T object( *static_cast< T* >( ptr ) ) ;
En fait, je serais d'avis que 1) il faut préférer la copie, et 2) quand on copie, il faut le faire des deux côtés, pour éviter des problèmes de durée de vie. Ce qui me mène à la struct allouée dynamiquement. Ça reste ce qu'il y a de plus sûr.
-- James Kanze GABI Software http://www.gabi-soft.fr 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
Fabien LE LEZ <gramster@gramster.com> wrote in message
news:<b9idk01ct8tbu51ggnun6nqottrms1lam0@4ax.com>...
On Tue, 14 Sep 2004 12:22:15 +0200, "Eric Bart"
<eb-adm@eric-bart.pasdepubmerci.net>:
J'aimerais transmettre un itérateur par la fonction pthread :
pthread_create (&th, NULL, axraAnnounceCid, (void *) &it);
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui
peuvent en faire joujou, ce qui limite la nécessité des locks.
La méthode générale pour faire ça est :
void * axraAnnounceCid(void * ptr)
{
T &t= *reinterpret_cast<T*>(ptr);
(où T est list<machin>::iterator )
mais note que l'objet d'origine doit toujours exister (sinon ton
"void*" ne pointe sur rien).
Il y a un problème de durée de vie dans tous les cas. La solution
« générale » consiste à allouer un struct dynamiquement, et d'y mettre
tout ce que on veut passer au thread. En phase de démarrage, le thread
copie alors les information de la struct aux endroits où il veut bien
l'avoir, et libère le struct.
Comme toute solution générale, elle peut être un peu lourde pour les cas
simples. Mais il ne faut jamais perdre de vue qu'on ne sait pas quand le
thread va réelement démarrer, par rapport au thread qui appelle
pthread_create. Il ne faut donc jamais que quelque chose dont on a passé
un pointeur ou une référence cesse de vivre avant qu'on a eu une
indication réele du thread qu'il n'en a plus besoin.
Si tu veux copier l'objet, je serais d'avis de le faire
explicitement :
void * axraAnnounceCid(void * ptr)
{
T &t_reference= *reinterpret_cast<T*>(ptr);
T copie_de_lobjet (t_reference);
Où est la différence par rapport à :
T object( *static_cast< T* >( ptr ) ) ;
En fait, je serais d'avis que 1) il faut préférer la copie, et 2) quand
on copie, il faut le faire des deux côtés, pour éviter des problèmes de
durée de vie. Ce qui me mène à la struct allouée dynamiquement. Ça reste
ce qu'il y a de plus sûr.
--
James Kanze GABI Software http://www.gabi-soft.fr
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
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui peuvent en faire joujou, ce qui limite la nécessité des locks.
La méthode générale pour faire ça est :
void * axraAnnounceCid(void * ptr) { T &t= *reinterpret_cast<T*>(ptr);
(où T est list<machin>::iterator )
mais note que l'objet d'origine doit toujours exister (sinon ton "void*" ne pointe sur rien).
Il y a un problème de durée de vie dans tous les cas. La solution « générale » consiste à allouer un struct dynamiquement, et d'y mettre tout ce que on veut passer au thread. En phase de démarrage, le thread copie alors les information de la struct aux endroits où il veut bien l'avoir, et libère le struct.
Comme toute solution générale, elle peut être un peu lourde pour les cas simples. Mais il ne faut jamais perdre de vue qu'on ne sait pas quand le thread va réelement démarrer, par rapport au thread qui appelle pthread_create. Il ne faut donc jamais que quelque chose dont on a passé un pointeur ou une référence cesse de vivre avant qu'on a eu une indication réele du thread qu'il n'en a plus besoin.
Si tu veux copier l'objet, je serais d'avis de le faire explicitement :
void * axraAnnounceCid(void * ptr) { T &t_reference= *reinterpret_cast<T*>(ptr); T copie_de_lobjet (t_reference);
Où est la différence par rapport à :
T object( *static_cast< T* >( ptr ) ) ;
En fait, je serais d'avis que 1) il faut préférer la copie, et 2) quand on copie, il faut le faire des deux côtés, pour éviter des problèmes de durée de vie. Ce qui me mène à la struct allouée dynamiquement. Ça reste ce qu'il y a de plus sûr.
-- James Kanze GABI Software http://www.gabi-soft.fr 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
kanze
Fabien LE LEZ wrote in message news:...
On Tue, 14 Sep 2004 13:27:20 +0200, "Eric Bart" :
j'aimerais faire un erase de cet itérateur.
Tu t'aventures là dans les méandres de la programmation multithread -- et en profites pour sortir du cadre du présent forum, mais je me permettrai une petite digression.
Pas vraiment. S'il veut des précisions concernante une API précise, il sort du cadre du groupe. Mais il me semble qu'on était d'accord qu'une discussion plus général sur les problèmes de threading était acceptable, étant donné qu'ils sont les mêmes (ou très semblables) sur tous les systèmes.
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle. Il faut bien entendu que le "petit trafic" en question soit le plus court possible, car le mutex peut avoir pour effet de bloquer les autres threads.
C'est une bonne règle générale. Elle vaut sous Posix, pour les types de base et les types connus de Posix. Pour les types C++, il faut démander ce que garantit l'implémentation de la classe dont on se sert. La bibliothèque standard de la SGI donne les même garanties que Posix, mais ce n'est pas le cas de toutes les bibliothèques -- avec la bibliothèque standard de g++, par exemple, il faut systèmatiquement protéger tous les accès, y compris si l'objet n'est jamais modifié nulle part.
Pour cette raison, je conseille de limiter le plus possible le nombre de données partagées.
D'autant plus que plus il y a de données partagées, plus il y a de risque d'un accès accidentel non protégé.
Note bien aussi que la protection doit servir aussi à s'assurer les invariantes du programme. Dans la pratique, ces invariantes concernent prèsque toujours plusieurs objets. Dans ces cas-là, il faut que le mutex protège l'ensemble des opérations, et non seulement chaque objet.
Dans ton cas, les données partagées sont : - le std::list<> - l'itérateur Note que tu dois garder une référence sur l'itérateur (et pas le copier), pour que les deux threads gardent le même objet. Et surtout, tu dois mettre un mutex à chaque fois que tu accèdes (en lecture ou écriture) à l'itérateur.
peut-on de faire une comparaison entre l'itérateur en référence et l'itérateur en recopie. S'il diffère, il y a eu un erase ... non ?
T tr = *reinterpret_cast<T*>(ptr); T tc (tr); if(tr!=tc)
Je ne connais pas assez la programmation multithread pour avoir un avis là-dessus... mais note que "tr" n'est pas une référence (faute de frappe ?)
Ça n'a rien à voir avec le multithread. À la suite d'un erase, tout itérateur désignant l'objet effacé est invalidé. C-à-d que simplement lire l'itérateur a un comportement indéfini.
-- James Kanze GABI Software http://www.gabi-soft.fr 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
Fabien LE LEZ <gramster@gramster.com> wrote in message
news:<smldk0d3tab6b17jtks3v5vpdrl10f4b9l@4ax.com>...
On Tue, 14 Sep 2004 13:27:20 +0200, "Eric Bart"
<eb-adm@eric-bart.pasdepubmerci.net>:
j'aimerais faire un erase de cet itérateur.
Tu t'aventures là dans les méandres de la programmation multithread --
et en profites pour sortir du cadre du présent forum, mais je me
permettrai une petite digression.
Pas vraiment. S'il veut des précisions concernante une API précise, il
sort du cadre du groupe. Mais il me semble qu'on était d'accord qu'une
discussion plus général sur les problèmes de threading était acceptable,
étant donné qu'ils sont les mêmes (ou très semblables) sur tous les
systèmes.
En programmation multithread, si deux threads peuvent accéder en même
temps au même objet, dont au moins un en écriture, il faut mettre un
mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux
autres threads d'y accéder, y fait son petit trafic, et relâche le
contrôle. Il faut bien entendu que le "petit trafic" en question soit
le plus court possible, car le mutex peut avoir pour effet de bloquer
les autres threads.
C'est une bonne règle générale. Elle vaut sous Posix, pour les types de
base et les types connus de Posix. Pour les types C++, il faut démander
ce que garantit l'implémentation de la classe dont on se sert. La
bibliothèque standard de la SGI donne les même garanties que Posix, mais
ce n'est pas le cas de toutes les bibliothèques -- avec la bibliothèque
standard de g++, par exemple, il faut systèmatiquement protéger tous les
accès, y compris si l'objet n'est jamais modifié nulle part.
Pour cette raison, je conseille de limiter le plus possible le nombre
de données partagées.
D'autant plus que plus il y a de données partagées, plus il y a de
risque d'un accès accidentel non protégé.
Note bien aussi que la protection doit servir aussi à s'assurer les
invariantes du programme. Dans la pratique, ces invariantes concernent
prèsque toujours plusieurs objets. Dans ces cas-là, il faut que le mutex
protège l'ensemble des opérations, et non seulement chaque objet.
Dans ton cas, les données partagées sont :
- le std::list<>
- l'itérateur
Note que tu dois garder une référence sur l'itérateur (et pas le
copier), pour que les deux threads gardent le même objet. Et surtout,
tu dois mettre un mutex à chaque fois que tu accèdes (en lecture ou
écriture) à l'itérateur.
peut-on de faire une comparaison entre l'itérateur en référence et
l'itérateur en recopie. S'il diffère, il y a eu un erase ... non ?
T tr = *reinterpret_cast<T*>(ptr);
T tc (tr);
if(tr!=tc)
Je ne connais pas assez la programmation multithread pour avoir un
avis là-dessus... mais note que "tr" n'est pas une référence (faute de
frappe ?)
Ça n'a rien à voir avec le multithread. À la suite d'un erase, tout
itérateur désignant l'objet effacé est invalidé. C-à-d que simplement
lire l'itérateur a un comportement indéfini.
--
James Kanze GABI Software http://www.gabi-soft.fr
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
Tu t'aventures là dans les méandres de la programmation multithread -- et en profites pour sortir du cadre du présent forum, mais je me permettrai une petite digression.
Pas vraiment. S'il veut des précisions concernante une API précise, il sort du cadre du groupe. Mais il me semble qu'on était d'accord qu'une discussion plus général sur les problèmes de threading était acceptable, étant donné qu'ils sont les mêmes (ou très semblables) sur tous les systèmes.
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle. Il faut bien entendu que le "petit trafic" en question soit le plus court possible, car le mutex peut avoir pour effet de bloquer les autres threads.
C'est une bonne règle générale. Elle vaut sous Posix, pour les types de base et les types connus de Posix. Pour les types C++, il faut démander ce que garantit l'implémentation de la classe dont on se sert. La bibliothèque standard de la SGI donne les même garanties que Posix, mais ce n'est pas le cas de toutes les bibliothèques -- avec la bibliothèque standard de g++, par exemple, il faut systèmatiquement protéger tous les accès, y compris si l'objet n'est jamais modifié nulle part.
Pour cette raison, je conseille de limiter le plus possible le nombre de données partagées.
D'autant plus que plus il y a de données partagées, plus il y a de risque d'un accès accidentel non protégé.
Note bien aussi que la protection doit servir aussi à s'assurer les invariantes du programme. Dans la pratique, ces invariantes concernent prèsque toujours plusieurs objets. Dans ces cas-là, il faut que le mutex protège l'ensemble des opérations, et non seulement chaque objet.
Dans ton cas, les données partagées sont : - le std::list<> - l'itérateur Note que tu dois garder une référence sur l'itérateur (et pas le copier), pour que les deux threads gardent le même objet. Et surtout, tu dois mettre un mutex à chaque fois que tu accèdes (en lecture ou écriture) à l'itérateur.
peut-on de faire une comparaison entre l'itérateur en référence et l'itérateur en recopie. S'il diffère, il y a eu un erase ... non ?
T tr = *reinterpret_cast<T*>(ptr); T tc (tr); if(tr!=tc)
Je ne connais pas assez la programmation multithread pour avoir un avis là-dessus... mais note que "tr" n'est pas une référence (faute de frappe ?)
Ça n'a rien à voir avec le multithread. À la suite d'un erase, tout itérateur désignant l'objet effacé est invalidé. C-à-d que simplement lire l'itérateur a un comportement indéfini.
-- James Kanze GABI Software http://www.gabi-soft.fr 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
Fabien LE LEZ
On 14 Sep 2004 23:46:39 -0700, :
Attention, tu tente ici une copie de l'itérateur.
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui peuvent en faire joujou, ce qui limite la nécessité des locks.
Pour un itérateur, ou toute autre forme de pointeur, c'est moins vrai : certes, on est sûr que l'itérateur ne sera pas modifié, mais on ne sait rien de la variable pointée ; on ne sait même pas si elle continuera à exister.
-- ;-)
On 14 Sep 2004 23:46:39 -0700, kanze@gabi-soft.fr:
Attention, tu tente ici une copie de l'itérateur.
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui
peuvent en faire joujou, ce qui limite la nécessité des locks.
Pour un itérateur, ou toute autre forme de pointeur, c'est moins
vrai : certes, on est sûr que l'itérateur ne sera pas modifié, mais on
ne sait rien de la variable pointée ; on ne sait même pas si elle
continuera à exister.
C'est souvent préférable. Comme ça, tu sais que tu es le seul qui peuvent en faire joujou, ce qui limite la nécessité des locks.
Pour un itérateur, ou toute autre forme de pointeur, c'est moins vrai : certes, on est sûr que l'itérateur ne sera pas modifié, mais on ne sait rien de la variable pointée ; on ne sait même pas si elle continuera à exister.
-- ;-)
Fabien LE LEZ
On 14 Sep 2004 23:46:39 -0700, :
Il y a un problème de durée de vie dans tous les cas. La solution « générale » consiste à allouer un struct dynamiquement
Tout en gérant les cas où le thread ne peut pas démarrer, et donc ne peut pas appeler delete.
-- ;-)
On 14 Sep 2004 23:46:39 -0700, kanze@gabi-soft.fr:
Il y a un problème de durée de vie dans tous les cas. La solution
« générale » consiste à allouer un struct dynamiquement
Tout en gérant les cas où le thread ne peut pas démarrer, et donc ne
peut pas appeler delete.
Il y a un problème de durée de vie dans tous les cas. La solution « générale » consiste à allouer un struct dynamiquement
Tout en gérant les cas où le thread ne peut pas démarrer, et donc ne peut pas appeler delete.
Ça dépend. En général, dans ce cas-là, j'appelle abort() assez vite. Alors, les fuites de mémoire, ça m'est un peu égal.
-- James Kanze GABI Software http://www.gabi-soft.fr 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
Sébastien Fraigneau
"Fabien LE LEZ" a écrit dans le message de news:
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle.
J'ajouterai qu'il est préférable de relacher l'objet dans le destructeur du mutex pour qu'en cas d'exception pendant le contrôle, l'objet ne reste pas bloqué.
"Fabien LE LEZ" <gramster@gramster.com> a écrit dans le message de
news:smldk0d3tab6b17jtks3v5vpdrl10f4b9l@4ax.com...
En programmation multithread, si deux threads peuvent accéder en même
temps au même objet, dont au moins un en écriture, il faut mettre un
mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux
autres threads d'y accéder, y fait son petit trafic, et relâche le
contrôle.
J'ajouterai qu'il est préférable de relacher l'objet dans le destructeur du
mutex pour qu'en cas d'exception pendant le contrôle, l'objet ne reste pas
bloqué.
En programmation multithread, si deux threads peuvent accéder en même temps au même objet, dont au moins un en écriture, il faut mettre un mutex : un thread "prend le contrôle" d'un objet, ce qui interdit aux autres threads d'y accéder, y fait son petit trafic, et relâche le contrôle.
J'ajouterai qu'il est préférable de relacher l'objet dans le destructeur du mutex pour qu'en cas d'exception pendant le contrôle, l'objet ne reste pas bloqué.