[C++ .NET] Comment passer un pointeur d'objet managé à un thread?
Dernière réponse : dans Programmation
Bonjour tout le monde!
Je vous préviens, c'est gros xD Tellement qu'une mise en place du problème doit être faite
Allons-y gaiement!
Voilà, je me retrouve confronté à un gros problème et malgré différentes possibilités explorées, il m'est apparemment impossible d'effectuer ce que j'essaie de faire.
Le blème en très cour
==> Comment parvenir à amener mon pointeur jusque dans ce thread bien loin??? ^^
Résumé de l'architecture:
Je mets en place une communication UDP via la classe UDPClient en C++ .NET. Un intervenant est ma classe de communication CLantronix qui possède des méthodes telles que "envoiTrame" ou encore (et surtout) "startEcoute". starEcoute est représente une reception asynchrone en udp. Dès qu'il y en a une qui survient, l'idéal est qu'elle place le bytes recu dans un buffer qu'on lui a préalablement passé en paramètre.
Le second intervenant est la classe CThreadEcoute qui ne sert qu'à contenir la méthode "threadée" d'écoute. Pourquoi une classe à part? parce qu'elle a besoin de paramètres. Donc une instance est créée avec les paramètres nécéssaires, et ensuite utilisée dans la création du thread (gcnew ThreadStart(...) ).
Extraits de codes:
Classe CLantronix
{
private:
//Variables de communication
UdpClient^ ClientUDP;
IPEndPoint^ NoeudIpDistant;
String^ IpDestination;
int PortDestination;
static bool EcouteEnCours = false;
static bool MessageRecu = false;
//Variable concernant le threading
CThreadEcoute^ oThreadEcoute;
Thread^ tEcoute;
Thread^ tAttente;
void attente();
public:
//Constructeurs
CLantronix(String^ I, int P);
//La méthode d'envoi (sous deux formes)
bool envoiTrame(String^ Chaine);
bool envoiTrame(char* Chaine);
//La reception synchrone (fonctionne sans problème)
bool receptionTrame(interior_ptr<array<Byte>^> BufferReception);
//La reception asynchrome, voici la kwak ^^
bool startEcoute(interior_ptr<array<Byte>^> BufferReception);
bool stopEcoute();
};
La classe CThreadEcoute:
{
public:
CThreadEcoute(int PE, UdpClient^, interior_ptr<array<Byte>^> BR);
//La méthode "Threadée"
static void executerThread();
static bool MessageRecu;
private:
//C'est ca qu'il me faudrait idéalement, mais c'est interdit par le language...
//static interior_ptr<array<Byte>^> BufferReception;
static int PortEcoute;
static UdpClient^ ClientUDP;
static IPEndPoint^ NoeudIpDistant;
//Méthode lancée lors de l'arrivée d'un paquet udp
static void traiterMessage(IAsyncResult^ asyncResult);
};
Explication du stuut:
Le but initial est de pourvoir, à partir d'un main ou quoi, effectuer une réception asynchrone comme suit:
ObjetCLantronix->startEcoute(&BytesRecus);
Cet appel est non bloquant (principe asynchrone), et le programme ne s'arreterait pas la dessus. quand qqch arriverait, le buffer BytesRecus serait simplement rempli par les méthodes encapsulées.
La méthode startEcoute:
bool CLantronix::startEcoute(interior_ptr<array<Byte>^> BufferReception)
{
//Démarrage du thread d'écoute sur le port spécifié
oThreadEcoute = gcnew CThreadEcoute(PORT_ECOUTE, ClientUDP, BufferReception);
tEcoute = gcnew Thread(gcnew ThreadStart(oThreadEcoute->executerThread));
tEcoute->Name = "Thread Ecoute";
tEcoute->Start();
//Démarrage du thread d'attente (cf. plus bas)
tAttente = gcnew Thread(gcnew ThreadStart(this, &CLantronix::attente));
tAttente->Name = "Thread Attente";
tAttente->Start();
EcouteEnCour = true;
return true;
}
Comme on peut le constater, cette méthode instancie une classe CThreadEcoute pour pouvoir lui passer les paramètre dont elle a besoin, avant de lancer en Thread la méthode executerThread de cette dernière.
Elle lance également un second thread dont elle possède elle meme la méthode. celui ci à pour rôle de surveiller le premier thread afin de savoir quand il a reçu qqch. Dans ce cas, elle le tue, et se tue ensuite. Donc la réception asynchrone recevra un message et un seul, après quoi tous les intervenants sont tués. La voici a titre indicatif, mais là ne se situe pas le problème:
La méthode "Threadée" attente:
{
//tant qu'il n'y a pas eu de message on attend et on passe la main
while(!oThreadEcoute->MessageRecu) Thread::Sleep(100);
stopEcoute();
}
On commence avec la première partie interressante maintenant, la méthode "threadée" de la classe CThreadEcoute:
{
UdpState^ EtatUDP = gcnew UdpState();
EtatUDP->NoeudIpDistant = NoeudIpDistant;
EtatUDP->ClientUDP = ClientUDP;
//On commence l'écoute
ClientUDP->BeginReceive(gcnew AsyncCallback(traiterMessage), EtatUDP);
MessageRecu = false;
//Si pas de message, on laisse un peu la main.
while (!MessageRecu)
{
Thread::Sleep(100);
}
}
=> qui appelle automatiquement la méthode traiterMessage quand qqch est arrivé:
{
UdpClient^ ClientUDP = ((UdpState^)(asyncResult->AsyncState))->ClientUDP;
IPEndPoint^ NoeudIpDistant = ((UdpState^)(asyncResult->AsyncState))->NoeudIpDistant;
try
{
*BufferReception = ClientUDP->EndReceive(asyncResult, NoeudIpDistant);
}
catch (Exception^){}
MessageRecu = true;
}
Et voici tout le noeud du problème: comment est-ce que je parvient à passer le pointeur "BufferReception" du tout début (passé dans la méthode startEcoute) jusqu'ici dans le thread d'écoute??
- Pas en paramètre car un thread est void xxx (void) d'office
- Pas de variable membre pointeur dans la classe CThreadEcoute que je pourrait initialiser via le contructeur par que "An interior pointer cannot be declared as a member of a class."
(((((((
- Par pointeur "classique"? mais en écrivant:
il prend directement ca comme interior_prt<array<Byte>^> ... Peut-être un moyen de le forcer?
==> comment parvenir à amener mon pointeur jusque dans ce thread bien loin??? ^^
ça c'est du problème hein
:yaisse2:
Merciiiii d'avance aux plus courageux d'entre vous. Votre est de la plus grande bienvenue
Je vous préviens, c'est gros xD Tellement qu'une mise en place du problème doit être faite
Allons-y gaiement!
Voilà, je me retrouve confronté à un gros problème et malgré différentes possibilités explorées, il m'est apparemment impossible d'effectuer ce que j'essaie de faire.
Le blème en très cour
==> Comment parvenir à amener mon pointeur jusque dans ce thread bien loin??? ^^Résumé de l'architecture:
Je mets en place une communication UDP via la classe UDPClient en C++ .NET. Un intervenant est ma classe de communication CLantronix qui possède des méthodes telles que "envoiTrame" ou encore (et surtout) "startEcoute". starEcoute est représente une reception asynchrone en udp. Dès qu'il y en a une qui survient, l'idéal est qu'elle place le bytes recu dans un buffer qu'on lui a préalablement passé en paramètre.
Le second intervenant est la classe CThreadEcoute qui ne sert qu'à contenir la méthode "threadée" d'écoute. Pourquoi une classe à part? parce qu'elle a besoin de paramètres. Donc une instance est créée avec les paramètres nécéssaires, et ensuite utilisée dans la création du thread (gcnew ThreadStart(...) ).
Extraits de codes:
Classe CLantronix
Citation :
ref class CLantronix{
private:
//Variables de communication
UdpClient^ ClientUDP;
IPEndPoint^ NoeudIpDistant;
String^ IpDestination;
int PortDestination;
static bool EcouteEnCours = false;
static bool MessageRecu = false;
//Variable concernant le threading
CThreadEcoute^ oThreadEcoute;
Thread^ tEcoute;
Thread^ tAttente;
void attente();
public:
//Constructeurs
CLantronix(String^ I, int P);
//La méthode d'envoi (sous deux formes)
bool envoiTrame(String^ Chaine);
bool envoiTrame(char* Chaine);
//La reception synchrone (fonctionne sans problème)
bool receptionTrame(interior_ptr<array<Byte>^> BufferReception);
//La reception asynchrome, voici la kwak ^^
bool startEcoute(interior_ptr<array<Byte>^> BufferReception);
bool stopEcoute();
};
La classe CThreadEcoute:
Citation :
ref class CThreadEcoute{
public:
CThreadEcoute(int PE, UdpClient^, interior_ptr<array<Byte>^> BR);
//La méthode "Threadée"
static void executerThread();
static bool MessageRecu;
private:
//C'est ca qu'il me faudrait idéalement, mais c'est interdit par le language...
//static interior_ptr<array<Byte>^> BufferReception;
static int PortEcoute;
static UdpClient^ ClientUDP;
static IPEndPoint^ NoeudIpDistant;
//Méthode lancée lors de l'arrivée d'un paquet udp
static void traiterMessage(IAsyncResult^ asyncResult);
};
Explication du stuut:
Le but initial est de pourvoir, à partir d'un main ou quoi, effectuer une réception asynchrone comme suit:
Citation :
BytesRecus = gcnew array<Byte>(1);ObjetCLantronix->startEcoute(&BytesRecus);
Cet appel est non bloquant (principe asynchrone), et le programme ne s'arreterait pas la dessus. quand qqch arriverait, le buffer BytesRecus serait simplement rempli par les méthodes encapsulées.
La méthode startEcoute:
Citation :
//Lance une réception non bloquante. Dès qu'une trame asynchrone est lue, l'écoute se terminebool CLantronix::startEcoute(interior_ptr<array<Byte>^> BufferReception)
{
//Démarrage du thread d'écoute sur le port spécifié
oThreadEcoute = gcnew CThreadEcoute(PORT_ECOUTE, ClientUDP, BufferReception);
tEcoute = gcnew Thread(gcnew ThreadStart(oThreadEcoute->executerThread));
tEcoute->Name = "Thread Ecoute";
tEcoute->Start();
//Démarrage du thread d'attente (cf. plus bas)
tAttente = gcnew Thread(gcnew ThreadStart(this, &CLantronix::attente));
tAttente->Name = "Thread Attente";
tAttente->Start();
EcouteEnCour = true;
return true;
}
Comme on peut le constater, cette méthode instancie une classe CThreadEcoute pour pouvoir lui passer les paramètre dont elle a besoin, avant de lancer en Thread la méthode executerThread de cette dernière.
Elle lance également un second thread dont elle possède elle meme la méthode. celui ci à pour rôle de surveiller le premier thread afin de savoir quand il a reçu qqch. Dans ce cas, elle le tue, et se tue ensuite. Donc la réception asynchrone recevra un message et un seul, après quoi tous les intervenants sont tués. La voici a titre indicatif, mais là ne se situe pas le problème:
La méthode "Threadée" attente:
Citation :
void CLantronix::attente(){
//tant qu'il n'y a pas eu de message on attend et on passe la main
while(!oThreadEcoute->MessageRecu) Thread::Sleep(100);
stopEcoute();
}
On commence avec la première partie interressante maintenant, la méthode "threadée" de la classe CThreadEcoute:
Citation :
void CThreadEcoute::executerThread(void){
UdpState^ EtatUDP = gcnew UdpState();
EtatUDP->NoeudIpDistant = NoeudIpDistant;
EtatUDP->ClientUDP = ClientUDP;
//On commence l'écoute
ClientUDP->BeginReceive(gcnew AsyncCallback(traiterMessage), EtatUDP);
MessageRecu = false;
//Si pas de message, on laisse un peu la main.
while (!MessageRecu)
{
Thread::Sleep(100);
}
}
=> qui appelle automatiquement la méthode traiterMessage quand qqch est arrivé:
Citation :
void CThreadEcoute::traiterMessage(System::IAsyncResult ^asyncResult){
UdpClient^ ClientUDP = ((UdpState^)(asyncResult->AsyncState))->ClientUDP;
IPEndPoint^ NoeudIpDistant = ((UdpState^)(asyncResult->AsyncState))->NoeudIpDistant;
try
{
*BufferReception = ClientUDP->EndReceive(asyncResult, NoeudIpDistant);
}
catch (Exception^){}
MessageRecu = true;
}
Et voici tout le noeud du problème: comment est-ce que je parvient à passer le pointeur "BufferReception" du tout début (passé dans la méthode startEcoute) jusqu'ici dans le thread d'écoute??
- Pas en paramètre car un thread est void xxx (void) d'office
- Pas de variable membre pointeur dans la classe CThreadEcoute que je pourrait initialiser via le contructeur par que "An interior pointer cannot be declared as a member of a class."
(((((((- Par pointeur "classique"? mais en écrivant:
Citation :
startEcoute(&BufferReception)il prend directement ca comme interior_prt<array<Byte>^> ... Peut-être un moyen de le forcer?
==> comment parvenir à amener mon pointeur jusque dans ce thread bien loin??? ^^
ça c'est du problème hein
:yaisse2:Merciiiii d'avance aux plus courageux d'entre vous. Votre est de la plus grande bienvenue
Autres pages sur : net passer pointeur objet manage thread
Lassé par la pub ? Créez un compte
Bonjour
techniquement je peux pas aider, jamais touché au C++
mais ton problème c'est de faire communiquer 2 threads non
dans ce cas, tu as déjà regarder au niveau des tubes ?
un sujet qui en parle
http://www.cppfrance.com/infomsg_THREAD-TUBES_717315.as...
techniquement je peux pas aider, jamais touché au C++
mais ton problème c'est de faire communiquer 2 threads non
dans ce cas, tu as déjà regarder au niveau des tubes ?
un sujet qui en parle
http://www.cppfrance.com/infomsg_THREAD-TUBES_717315.as...
Citation :
Bonjourtechniquement je peux pas aider, jamais touché au C++
mais ton problème c'est de faire communiquer 2 threads non
dans ce cas, tu as déjà regarder au niveau des tubes ?
un sujet qui en parle
http://www.cppfrance.com/infomsg_THREAD-TUBES_717315.as...
J'ai trvaillé avec les pipes en c-unix par le passé, mais à ce qu'il me semble, ce sont des moyens de communications inter-process non? Ici je suis toujours dans le meme process, ca peut fonctionner tout de meme?
Effectivement, mon problème est de pouvoir passer un interior_ptr à mon thread...
Je continue à rechercher sur les pipes en .NET, voir si ca peut etre utile.
MErci en toutcas déjà
Sinon, d'autres idées? quelqu'un? merci à tous!
Déjà, le langage C++ Managed est une aberration qui n'aurait jamais dû exister. Je te conseille de l'abandonner pour le C#.
Je n'ai pas lu le post initial, si ma réponse n'est pas bonne, je lirai
Pour les pipes, effectivement c'est entre les process. La différence entre les process et les thread, c'est la gestion de la mémoire : avec les thread, la mémoire est partagée. Tu peux donc partager une ressource entre plusieurs thread dans un même process. Evidemment, il faut éviter les problèmes d'accès concurrent, il faut donc utiliser les mutex (c'est finalement le mieux) ou les sémaphores.
http://msdn2.microsoft.com/en-us/library/system.threading.mutex.aspx
Je n'ai pas lu le post initial, si ma réponse n'est pas bonne, je lirai
Pour les pipes, effectivement c'est entre les process. La différence entre les process et les thread, c'est la gestion de la mémoire : avec les thread, la mémoire est partagée. Tu peux donc partager une ressource entre plusieurs thread dans un même process. Evidemment, il faut éviter les problèmes d'accès concurrent, il faut donc utiliser les mutex (c'est finalement le mieux) ou les sémaphores.
http://msdn2.microsoft.com/en-us/library/system.threading.mutex.aspx
Merci pour vos suggestions les gars
J'ai réfléchit au truc cette nuit ^^ et la re-suis au taf donc je vais tester: J'ai deux "solutions potentielles". La première idée: est-ce nécéssaire de threader ma méthode d'écoute appellée "executerThread"? Si je ne le fait pas, la boucle
while (!MessageRecu)
{
Thread::Sleep(100);
}
laisserait-elle quand meme la main ou mangerait-t-elle le processeur comme pas possible? Si je ne thread pas ce code, je pourrait en faire une méthode à paramètre (puisque plus de thread) et même tout rapatrier dans la classe CLantronix. Mais le problème qui s'en suivrait est toujours le fait que l'arrivage d'un mesasge provoque l'appel automatique de la méthode asynchrone "traiterMessage". Et c'est dans cette méthode qu'il me faudrait avoir accès à mon pointeur ^^ ==> est-ce que je faire en sorte de passer un paramètre a cette méthode?
Seconde solution, je pense avoir fait une erreure de syntaxe
Pour avoir un pointeur "classique" on va dire, d'array<Byte>^ , je dois écrire array<Byte>^ * ou bien array<Byte>* (j'opterais pour la seconde forme) ?
En tout un grand merci à vous les gars, peut de gens se penchent sur des stuut si gros ^^' j'en suis conscient
A très vite!
J'ai réfléchit au truc cette nuit ^^ et la re-suis au taf donc je vais tester: J'ai deux "solutions potentielles". La première idée: est-ce nécéssaire de threader ma méthode d'écoute appellée "executerThread"? Si je ne le fait pas, la boucleCitation :
//Si pas de message, on laisse un peu la main.while (!MessageRecu)
{
Thread::Sleep(100);
}
laisserait-elle quand meme la main ou mangerait-t-elle le processeur comme pas possible? Si je ne thread pas ce code, je pourrait en faire une méthode à paramètre (puisque plus de thread) et même tout rapatrier dans la classe CLantronix. Mais le problème qui s'en suivrait est toujours le fait que l'arrivage d'un mesasge provoque l'appel automatique de la méthode asynchrone "traiterMessage". Et c'est dans cette méthode qu'il me faudrait avoir accès à mon pointeur ^^ ==> est-ce que je faire en sorte de passer un paramètre a cette méthode?
Seconde solution, je pense avoir fait une erreure de syntaxe
Pour avoir un pointeur "classique" on va dire, d'array<Byte>^ , je dois écrire array<Byte>^ * ou bien array<Byte>* (j'opterais pour la seconde forme) ?En tout un grand merci à vous les gars, peut de gens se penchent sur des stuut si gros ^^' j'en suis conscient
A très vite!
bon -_-'
Déjà, ne pas threader "executerThread" ca va pas le faire, parce que meme si le Thread::Sleep(100); laisse la main à d'autres process, le bloc de code qui appellerait "executerThread" resterait callé tant que cette dernière est dans sa boucle... sleep ou pas... donc, je dois threader ce code.
Bon, reste plus que la solution pointeur classique.. si je parviens pas à faire un pointeur "classique" sur mon array<Byte>^, alors je sais pas comment me débloquer de cette situation
C'est quand même con a la base, je dois juste avoir accès à mon pointeur à partir de la méthode "traiterMessage" qui fait la réception proprement dite... snif!
Déjà, ne pas threader "executerThread" ca va pas le faire, parce que meme si le Thread::Sleep(100); laisse la main à d'autres process, le bloc de code qui appellerait "executerThread" resterait callé tant que cette dernière est dans sa boucle... sleep ou pas... donc, je dois threader ce code.
Bon, reste plus que la solution pointeur classique.. si je parviens pas à faire un pointeur "classique" sur mon array<Byte>^, alors je sais pas comment me débloquer de cette situation
C'est quand même con a la base, je dois juste avoir accès à mon pointeur à partir de la méthode "traiterMessage" qui fait la réception proprement dite... snif!
error C3699: '*' : cannot use this indirection on type 'cli::array<Type>'
......... -_____________-"
je vais le frapper xD
Bon, une troisième solution germe en ce moment ^^ Puisque pas moyen de faire gober ce pointeur d'array<Byte>^, il me faut passer par autre chose comme conteneur de données. qqch de non managé pour pouvoir avoir un pointeur dessus. tapper les donnée du receive dedans et parser ca dans le main :s
ca va fun, qui vaincra? (6)
......... -_____________-"
je vais le frapper xD
Bon, une troisième solution germe en ce moment ^^ Puisque pas moyen de faire gober ce pointeur d'array<Byte>^, il me faut passer par autre chose comme conteneur de données. qqch de non managé pour pouvoir avoir un pointeur dessus. tapper les donnée du receive dedans et parser ca dans le main :s
ca va fun, qui vaincra? (6)
Syntaxiquement, c'est ok, ca passe : Je passe tout au début du processus non plus un pointeur d'array<Byte>, mais bien un unsigned char*. lui, je peux le stocker et donc l'envoyer juque dans mon thread d'écoute.
Quand je fais le receive(..), je réceptionne dans un array<Byte>^ temporaire quand je convertis en un par un et que je tape dans mon unsigned char* passé au début
La méthode traiterMessage est devenue
{
UdpClient^ ClientUDP = ((UdpState^)(asyncResult->AsyncState))->ClientUDP;
IPEndPoint^ NoeudIpDistant = ((UdpState^)(asyncResult->AsyncState))->NoeudIpDistant;
try
{
array<Byte>^ temp = ClientUDP->EndReceive(asyncResult, NoeudIpDistant);
BufferReception = new unsigned char[temp->Length];
for(int i=0; i < temp->Length ;i++)
{
*(BufferReception+i) = (unsigned char)temp->GetValue(i);
}
}
catch (Exception^){}
MessageRecu = true;
}
Mais ca marche toujours pas, j'ai rien dans mon "BufferReception"... Je-vais-trouver ^^
Quand je fais le receive(..), je réceptionne dans un array<Byte>^ temporaire quand je convertis en un par un et que je tape dans mon unsigned char* passé au début
La méthode traiterMessage est devenue
Citation :
void CThreadEcoute::traiterMessage(System::IAsyncResult ^asyncResult){
UdpClient^ ClientUDP = ((UdpState^)(asyncResult->AsyncState))->ClientUDP;
IPEndPoint^ NoeudIpDistant = ((UdpState^)(asyncResult->AsyncState))->NoeudIpDistant;
try
{
array<Byte>^ temp = ClientUDP->EndReceive(asyncResult, NoeudIpDistant);
BufferReception = new unsigned char[temp->Length];
for(int i=0; i < temp->Length ;i++)
{
*(BufferReception+i) = (unsigned char)temp->GetValue(i);
}
}
catch (Exception^){}
MessageRecu = true;
}
Mais ca marche toujours pas, j'ai rien dans mon "BufferReception"... Je-vais-trouver ^^
Merci a tous ceux qui ont yeutés un jette
J'ai résolu tout ca en me passant du array<Byte>^. J'ai choisi de travailler avec un buffer de type unsigned char* passé au début. De cette manière pas mal de chose ont pu etre résolues: plus de seconde classe "CThreadEcoute", j'ai tout rapatrié dans la classe CLantronix; possibilté de stocke le pointeur uchar* et donc accessible au thread d'écoute
. Ca marche nikel maintenant :king:
Merci tous
J'ai résolu tout ca en me passant du array<Byte>^. J'ai choisi de travailler avec un buffer de type unsigned char* passé au début. De cette manière pas mal de chose ont pu etre résolues: plus de seconde classe "CThreadEcoute", j'ai tout rapatrié dans la classe CLantronix; possibilté de stocke le pointeur uchar* et donc accessible au thread d'écoute
. Ca marche nikel maintenant :king:Merci tous
Et tu as pensé aux accès concurrents?
C'est-à-dire si tu lis ton buffer alors que quelqu'un écrit de dedans, il peux arriver que tu lises le buffer dont la moitié est le buffer avant, et l'autre moitié après écriture partielle. D'où l'utilité du mutex qui permet de s'assurer que si un thread utilise le buffer, les autres thread sont mis en attente.
C'est-à-dire si tu lis ton buffer alors que quelqu'un écrit de dedans, il peux arriver que tu lises le buffer dont la moitié est le buffer avant, et l'autre moitié après écriture partielle. D'où l'utilité du mutex qui permet de s'assurer que si un thread utilise le buffer, les autres thread sont mis en attente.
Lassé par la pub ? Créez un compte
- Contenus similaires :
Tags :
- ForumLogiciel 3d architecture
- articlesSous réseau classe c
- ForumLogiciel de architecture
- solutionsCherche logiciel architecture interieur
- ForumDifference processeur intel amd
- ForumProcesseur amd sempron 2800
- ForumIntel core 2 duo e4300
- ForumConseil processeur portable
- ForumProbleme demarrage portable packard bell
- ForumArchitecture client serveur multitiers
- Voir plus