OVH Cloud OVH Cloud

conversion d'un itérateur vers void *

19 réponses
Avatar
Eric Bart
Bonjour,

J'aimerais transmettre un itérateur par la fonction pthread :
pthread_create (&th, NULL, axraAnnounceCid, (void *) &it);

Et bien sûr j'aimerais le récupérer
void * axraAnnounceCid(void * it1)
{
list<stCdial>::iterator it2 = *it1;


Et bien sûr ça ne marche pas.

Comment faire ça proprement ? Merci.

9 réponses

1 2
Avatar
Jean-Marc Bourguet
"Eric Bart" writes:

"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



Avatar
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


Avatar
Fabien LE LEZ
http://www.giromini.org/usenet-fr/repondre.html

--
;-)
Avatar
kanze
Fabien LE LEZ wrote in message
news:...
On Tue, 14 Sep 2004 12:22:15 +0200, "Eric Bart"
:

J'aimerais transmettre un itérateur par la fonction pthread :
pthread_create (&th, NULL, axraAnnounceCid, (void *) &it);


OK.

void * axraAnnounceCid(void * it1)
{
list<stCdial>::iterator it2 = *it1;


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.

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


Avatar
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


Avatar
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.


--
;-)


Avatar
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.


--
;-)

Avatar
kanze
Fabien LE LEZ wrote in message
news:...
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.


Ç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


Avatar
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é.

1 2