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.

10 réponses

1 2
Avatar
Fabien LE LEZ
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.

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

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);



--
;-)

Avatar
Eric Bart
Merci

T &t= *reinterpret_cast<T*>(ptr);


Si j'ai bien compris, le & veut dire que le compilateur doit
prendre la même adresse mémoire que ptr pour t. non ?
Transmission par référence ...

Avatar
Fabien LE LEZ
On Tue, 14 Sep 2004 12:56:48 +0200, "Eric Bart"
:

T &t= *reinterpret_cast<T*>(ptr);


Si j'ai bien compris, le & veut dire que


Le "&" indique ici que "t" est une référence sur l'objet d'origine.

le compilateur doit
prendre la même adresse mémoire que ptr pour t.


En pratique, c'est ça.

Si tu fais un

T t= *reinterpret_cast<T*>(ptr);

tu crées d'abord une référence constante sur l'objet initial (passé
via ptr), puis tu appelles le constructeur de T avec cette référence
comme paramètre ; c'est équivalent à :

T const& temporaire= *reinterpret_cast<T*>(ptr);
T t (temporaire);




--
;-)


Avatar
Eric Bart
Merci encore ...

et encore une ptite question ...

j'aimerais faire un erase de cet itérateur. Pourtant il se peut
très bien qu'une thread continue de travailler sur ce même itérateur
et qu'il y ait un bug.

J'aimerais résoudre ce problème sans utiliser une fonction de la
lib thread.

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 ?

T tr = *reinterpret_cast<T*>(ptr);
T tc (tr);
if(tr!=tc)
...
Avatar
Fabien LE LEZ
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.
Pour cette raison, je conseille de limiter le plus possible le nombre
de données partagées.

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 ?)


--
;-)

Avatar
Eric Bart
Merci

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 ?)


Oui faute de frappe. Heureusement que j'ai quand même réussi à comprendre
la siginfication du & :o)


Avatar
Jean-Marc Bourguet
"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.

Il n'y a aucun moyen standard pour verifier la validite d'un
iterateur.

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
Fabien LE LEZ
On Tue, 14 Sep 2004 13:27:20 +0200, "Eric Bart"
:

j'aimerais faire un erase de cet itérateur


En fait, je te conseille de passer au deuxième thread non pas un
itérateur, mais un objet du type :

struct Machin
{
T* bidule;
bool bidule_est_valide;
};

Donc, quand tu veux supprimer l'objet, tu :
- mets un mutex
- supprimes l'objet
- mets bidule_est_valide à false
- vires le mutex


--
;-)

Avatar
Eric Bart
Oui mais il faut bien aussi supprimmer la structure un jour.

Qu'est-ce qui me dit que cette structure dans thread 1 n'a
pas été supprimmée dans thread 2 ?

On revient ptêt au même problème ...

"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


En fait, je te conseille de passer au deuxième thread non pas un
itérateur, mais un objet du type :

struct Machin
{
T* bidule;
bool bidule_est_valide;
};

Donc, quand tu veux supprimer l'objet, tu :
- mets un mutex
- supprimes l'objet
- mets bidule_est_valide à false
- vires le mutex


--
;-)



Avatar
Eric Bart
"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

thread 1
pthread_create (&th, NULL, axraAnnounceCid, (void *) &it);
...
it=erase(it);

thread 2
void * axraAnnounceCid(void * it)
{
T &tr = *reinterpret_cast<T*>(it);
T tc (tr);
if(tr!=tc) //pour détecter la validité
...


De toutes façons, ptêt qu'au moment de la recopie de it dans thread 2,
it ne sera déjà même plus valide.
Fo ptêt mieux ke je passe une structure


1 2