[C++] Classe Thread (ca marche)

Classe Thread (ca marche) [C++] - C++ - Programmation

Marsh Posté le 28-01-2004 à 23:21:15    

-edit-
RESOLU
Je réinvente la roue ! Je code une classe C++ qui encapsule les threads POSIX. Ca fonctionne bien sous Win32(MinGW) mais ca plante complètement sous Linux(g++).
RESOLU
-edit-
 
-edit-
Ne pas oublier de liker explicitement avec pthread.
-edit-
 
Voici le code:
 

Code :
  1. // Librairies C++ & STL
  2. #include<string>
  3. #include<iostream>
  4. // Librairies supplémentaires spéicifques Win32 ou GNU/Linux
  5. #ifdef WIN32
  6. #include<windows.h>
  7. #include<winbase.h>
  8. #include<process.h>
  9. #else
  10. #include<unistd.h>
  11.     #include<pthread.h>
  12. #endif
  13. // "Emulation" de quelques fonctions POSIX pour Win32
  14. #ifdef WIN32
  15. #define THREAD_FUNCTION void
  16. #define pthread_t HANDLE
  17. #define pthread_create(thhandle,attr,thfunc,tharg) ((*thhandle=(HANDLE)_beginthread(thfunc,0,tharg))==NULL)
  18. #define pthread_join(thread) ((WaitForSingleObject((thread),INFINITE)!=WAIT_OBJECT_0) || !CloseHandle(thread))
  19. #define pthread_detach(thread) if(thread!=NULL)CloseHandle(thread)
  20. #define pthread_exit(retval) _endthread();
  21. #define pthread_mutex_t HANDLE
  22. #define pthread_mutex_init(object,attr) *object=CreateMutex(NULL,false,NULL)
  23. #define pthread_mutex_destroy(object) CloseHandle(*object)#define pthread_mutex_lock(object) WaitForSingleObject(*object,INFINITE)
  24. #define pthread_mutex_unlock(object) ReleaseMutex(*object)
  25. #define sleep(nb) Sleep(nb000)
  26. #else
  27. #define THREAD_FUNCTION void *
  28. #endif
  29. // Classe de base : x_Filament exécute la fonction membre ::Traitement() de la classe dérivée. L'exécution de ::Traitement() met en oeuvre un filament (ou encore un 'thread' en anglais).
  30. class x_Filament
  31. {
  32. public:
  33. // Demarrer() crée un filament qui execute le traitement avec passage de l'argument
  34. int Demarrer( void * );
  35. // L'argument du filament
  36. void * Argument_Filament;
  37. // Le code du filament à surcharger par la classe dérivée
  38. virtual void Traitement( void * ) = 0;
  39. private:
  40. // L'identifiant du filament
  41. pthread_t Identifiant_Filament;
  42. };
  43. // Le 'Thread' qui execute le traitement avec passage de l'argument
  44. static THREAD_FUNCTION Filament( void * pthis ) {
  45. x_Filament * pParent = (x_Filament*)pthis;
  46. pParent->Traitement( pParent->Argument_Filament );
  47. pthread_exit(NULL);
  48. };
  49. // Demarrer() crée un filament qui execute le traitement avec passage de l'argument
  50. int x_Filament::Demarrer( void * argument ) {
  51.   Argument_Filament = argument;
  52.   int Valeur_Retour = pthread_create( &Identifiant_Filament, NULL, Filament, this );
  53.   return Valeur_Retour;
  54. };
  55. // Exemple de mise en oeuvre de classes dérivée de x_Filament.
  56. // Classe dérivée : x_MaClasse
  57. // (non suffisamment idiot pour faire comprendre qu'il s'agit d'un exemple). Cette classe décompte le temps qui passe (en secondes). Un compteur temporel est donc initialisé dans le constructeur et une fonction membre ::Traitement() assure l'auto-incrémentation du compteur temporel. Puisque cette classe dérive de x_Filament, une fois la fonction membre ::Demarrer() appelée, la fonction membre ::Traitement() s'exécute en parallèle du reste du code! Pour rendre cette classe un minimum "Thread-Safe", son écriture est légèrement chargée.   
  58. class x_MaClasse : public x_Filament
  59. {
  60. public:
  61. // Contructeur qui permet d'initialiser le compteur à une valeur quelconque
  62. x_MaClasse( long t ) {
  63.   lTempsInitial = lTemps = t;
  64.   pthread_mutex_init( &pmTemps, NULL ); }
  65. // Contructeur par recopie
  66. x_MaClasse( const x_MaClasse & c ) {
  67.   lTemps = c.lTemps;
  68.   lTempsInitial = c.lTempsInitial;
  69.   pmTemps = c.pmTemps; }
  70. // Fonction membre qui donne la valeur du compteur temporel
  71. long operator()() {
  72.   pthread_mutex_lock( &pmTemps );
  73.   long lValeurCourante = lTemps;
  74.   pthread_mutex_unlock( &pmTemps );
  75.   return lValeurCourante; }
  76. private:
  77. void Traitement( void * ) {
  78.   while( lTemps < ( lTempsInitial + 10 ) ) // on compte pendant 10s et on rend la main...
  79.   {
  80.     pthread_mutex_lock( &pmTemps );
  81.     lTemps++;
  82.     pthread_mutex_unlock( &pmTemps );
  83.     sleep(1);
  84.   }
  85. }
  86. long lTemps;
  87. long lTempsInitial;
  88. pthread_mutex_t pmTemps;
  89. };
  90. // Programme principal
  91. int main( int argc, char * argv[] )
  92. {
  93. // On instancie deux classes x_MaClasse : l'une démarre à -10s, l'autre à 90s.
  94. x_MaClasse monTemps10 = x_MaClasse(-10);
  95. x_MaClasse monTemps90 = x_MaClasse(90);
  96. // On démarre le filament (qui auto-incrémente le compteur temporel) de chaque classe.
  97. monTemps10.Demarrer( NULL );
  98. monTemps90.Demarrer( NULL );
  99. // On affiche régulièrement la valeur du compteur temporel de chaque classe
  100. while( true ) // <- PAS BIEN! Désolé!
  101. std::cout << "Etat des compteurs { " << monTemps10() << "s ; " << monTemps90() << "s }." << std::endl;
  102. // ...et pour la forme (hein?)
  103. return EXIT_SUCCESS;
  104. }


 
-edit-
RESOLU
Sous GNU/Linux, voici les problemes :
- Segmentation Fault au passage de l'instruction pthread_create(...).
- Impossible de linker certaines fonctions de pthread (pthread_join/detach entre autres).
RESOLU
-edit-
 
Merci d'avance pour vos conseils eclairés.
 
Cordialement,
   Xter.


Message édité par xterminhate le 01-02-2004 à 21:02:20
Reply

Marsh Posté le 28-01-2004 à 23:21:15   

Reply

Marsh Posté le 28-01-2004 à 23:22:31    

jète tout et passe par là -> boost.org :sol:
en plus c'est C++ orienté objet, un régal

Reply

Marsh Posté le 28-01-2004 à 23:28:26    

Oui j'y ai fortement pensé... mais je voulais tenter de comprendre par moi même.
 
D'ailleurs, je n'ai pas encore capté comment on exploite boost::, les sources sont ils disponibles ou faut il necessairement passer par leurs packages et leur outil de "compilation" (je ne sais meme pas le nommer).
 
Merci.
  XteR.

Reply

Marsh Posté le 28-01-2004 à 23:33:24    

non, les bordels compilés sont disponibles sur 2 nombreux systèmes.

Reply

Marsh Posté le 29-01-2004 à 00:11:34    

Tu as quelle version de boost ?

Reply

Marsh Posté le 29-01-2004 à 00:12:43    

1.30.2-2

Reply

Marsh Posté le 29-01-2004 à 08:39:26    

La nuit porte conseil ! Mon code tourne parfaitement sous GNU/Linux a condition de demander explicitement de linker avec POSIX Thread.... (hum! pas sérieux ca!)
 
Remarque : Par contre, je me demande toujours pourquoi pthread_create() est linkable sans la librairie POSIX (pthread.h). Ou est-elle déclarée ailleurs ? Pourquoi est-elle buggée en plus ?
 
Passons, je vais qd même essayer de comprendre boost.
 
Merci,
   Xter.

Reply

Marsh Posté le 29-01-2004 à 08:58:22    

bon, j'ai viré la partie win32 qui ne m'interresse pas.
le code suivant fonctionne.
ALors c'est vrai que boost c'est bien, mais le module de thread ne va pas forcément à tout le monde. Notemment, la fonction executée dans le thread n'est pas une fonction membre, et le mécanisme que xterminhate met en place avec la fonction virtuelle pure est sympathique, et va au dela de ce qui est proposé par boost.
Enfin, même si c'est bien de ne pas réinventer le moteur a explosion, certains ont quand même envie de comprendre comment cela se passe. Et dans ces cas, mettre les mains dedans c'est bien aussi.
 
Bon, sinon si tu as des pb de link, c'est que ta lib doit être foireuse. normalement, seul un -lpthread devreait suffir.
 

Code :
  1. // Librairies C++ & STL
  2. #include<string>
  3. #include<iostream>
  4.    
  5. // Librairies supplémentaires spéicifques Win32 ou GNU/Linux
  6. #include<unistd.h>
  7. #include<pthread.h>
  8.  
  9. #define THREAD_FUNCTION void *
  10.  
  11. // Classe de base : x_Filament exécute la fonction membre ::Traitement()
  12. //  de la classe dérivée. L'exécution de ::Traitement() met en oeuvre
  13. //  un filament (ou encore un 'thread' en anglais).
  14. //
  15. class x_Filament 
  16. {
  17. public:
  18.    
  19. // Demarrer() crée un filament qui execute le traitement avec passage de l'argument
  20. int Demarrer()
  21.  {
  22.   return pthread_create( &Identifiant_Filament, NULL, Filament, this );
  23.  }
  24.    
  25. protected:
  26. // Le code du filament à surcharger par la classe dérivée
  27. virtual void Traitement() = 0; 
  28.    
  29. private:
  30. // Le 'Thread' qui execute le traitement avec passage de l'argument
  31. static
  32. THREAD_FUNCTION Filament( void * pthis )
  33.  {
  34.   x_Filament * pParent = (x_Filament*)pthis;
  35.   pParent->Traitement();
  36.   pthread_exit(NULL);
  37.  }
  38. // L'identifiant du filament
  39. pthread_t Identifiant_Filament;
  40. };
  41.  
  42. // Exemple de mise en oeuvre de classes dérivée de x_Filament.
  43.  
  44. // Classe dérivée : x_MaClasse
  45. //  (nom suffisamment idiot pour faire comprendre qu'il s'agit d'un exemple).
  46. //  Cette classe décompte le temps qui passe (en secondes). Un compteur
  47. //  temporel est donc initialisé dans le constructeur et une fonction
  48. //  membre ::Traitement() assure l'auto-incrémentation du compteur temporel.
  49. //  Puisque cette classe dérive de x_Filament, une fois la fonction
  50. //  membre ::Demarrer() appelée, la fonction membre ::Traitement() s'exécute
  51. //  en parallèle du reste du code! Pour rendre cette classe un minimum
  52. //  "Thread-Safe", son écriture est légèrement chargée.
  53. //
  54. class x_MaClasse : public x_Filament
  55. {
  56. public:
  57.      
  58. // Contructeur qui permet d'initialiser le compteur à une valeur quelconque
  59. x_MaClasse( long t )
  60.  {
  61.   lTempsInitial = lTemps = t;
  62.   pthread_mutex_init( &pmTemps, NULL );
  63.  }
  64.    
  65. // Contructeur par recopie
  66. x_MaClasse( const x_MaClasse & c )
  67.  {
  68.   lTemps = c.lTemps;
  69.   lTempsInitial = c.lTempsInitial;
  70.   pmTemps = c.pmTemps;
  71.  }
  72.      
  73. // Fonction membre qui donne la valeur du compteur temporel
  74. long operator()()
  75.  {
  76.   pthread_mutex_lock( &pmTemps );
  77.   long lValeurCourante = lTemps;
  78.   pthread_mutex_unlock( &pmTemps ); 
  79.   return lValeurCourante;
  80.  }
  81.      
  82. private:
  83.      
  84. void Traitement()
  85.  {
  86.   while( lTemps < ( lTempsInitial + 10 ) ) // on compte pendant 10s et on rend la main...
  87.   {
  88.    pthread_mutex_lock( &pmTemps );
  89.    ++lTemps;
  90.    pthread_mutex_unlock( &pmTemps );
  91.    sleep(1);
  92.   }
  93.  }
  94.      
  95. long lTemps;
  96. long lTempsInitial;
  97. pthread_mutex_t pmTemps;
  98. };
  99.  
  100. // Programme principal
  101. int main( int argc, char * argv[] )
  102. {
  103.      
  104. // On instancie deux classes x_MaClasse : l'une démarre à -10s, l'autre à 90s.
  105. x_MaClasse monTemps10 = x_MaClasse(-10);
  106. x_MaClasse monTemps90 = x_MaClasse(90);
  107.      
  108. // On démarre le filament (qui auto-incrémente le compteur temporel) de chaque classe.
  109. monTemps10.Demarrer();
  110. monTemps90.Demarrer();
  111.      
  112. // On affiche régulièrement la valeur du compteur temporel de chaque classe
  113. while( true ) // <- PAS BIEN! Désolé!
  114. {
  115.  std::cout << "Etat des compteurs { " << monTemps10() << "s ; " << monTemps90() << "s }." << std::endl;
  116.  sleep(1);
  117. }
  118.      
  119. // ...et pour la forme (hein?)
  120. return 0;
  121. }


Reply

Marsh Posté le 29-01-2004 à 11:10:54    

oui mais c'est pourri comme code et ça fout en l'air les invariants du C++. tu peux te gratter pour tes destructeurs, autant carrémen tplus les écrire
 
x_MaClasse monTemps10 = x_MaClasse(-10);  
 
t'es sur que tu connais pas plus simple comme syntaxe ?
 
 
    « // ...et pour la forme (hein?)
     return 0; »
 
inutile

Reply

Marsh Posté le 29-01-2004 à 11:31:00    

> oui mais c'est pourri comme code
 
bien d'accord avec cet argument. Mais avant de passer à du code pondu par qq1 d'autre, c'est quand même bien de comprendre pourquoi ce qu'on a fait ne fonctionne pas, non? C'est frustrant de passer à autre chose sans avoir compris la cause des problèmes (qu'on est donc succeptible de reproduire par la suite).

Reply

Marsh Posté le 29-01-2004 à 11:31:00   

Reply

Marsh Posté le 29-01-2004 à 11:37:47    

le problème n'est pas là. c'est une approche C avec du C++. tu prends n'importe quelle implémentation de thread dans un langage objet (C++ pour nous), tout est emballé dans des classes.

Reply

Marsh Posté le 29-01-2004 à 12:45:41    

SoWhatIn22, je vois que tu as simplifié ma petite classe Thread. Je comptais le faire aussi et de cette façon là, mais je constaste que tu m'a pris de vitesse. Initialement, la fonction static ::filament se situait dans la classe, tu as corrigé de toi même, parfait.
 
Ce code avait un objectif pédagogique et je souhaite l'améliorer. Je suis prenneur de toutes observations constructives pour faire les améliorations qu'il convient.
 
Je regarde le code Thread.cpp de boost en comparaison, mais je ne pense pas utiliser directement boost (dans un premier temps) car c'est une librairie 'globale' dont 99% des fonctionnalités ne me sont pas utiles à l'heure actuelle.
 
Concernant le probleme des destructeurs... et bien je vais y regarder de plus pres. Jusqu'a maintenant, ce n'etait pas mon soucis principal.
 
Cordialement,
   Xter.


Message édité par xterminhate le 29-01-2004 à 12:49:32
Reply

Marsh Posté le 29-01-2004 à 12:56:10    

bah c'est toi qui voit, c'est toi qui supporte un mauvais design et ses problèmes. À au fait, n'utilise pas STL, parce que là t'es à 1% d'utilisation, ça vaut pas la peine

Reply

Marsh Posté le 29-01-2004 à 14:22:19    

SoWhatIn22 a écrit :


ALors c'est vrai que boost c'est bien, mais le module de thread ne va pas forcément à tout le monde. Notemment, la fonction executée dans le thread n'est pas une fonction membre, et le mécanisme que xterminhate met en place avec la fonction virtuelle pure est sympathique, et va au dela de ce qui est proposé par boost.


 
bin l'enorme avantage de la 'fonction' a executer par le thread chez boost et que ca peut etre un fonctor, on peut utiliser boost::bind pour utiliser des objets, tu peux envoyer une fonction avec des paramètres aussi.
 
puis rien ne t'empeche (il me semble ?) de dériver boost::thread pour pouvoir limiter l'utilisation à une méthode du fils comme ici.
 
sinon, la plupart des fontionnalités de boost s'ont pas besoin d'être compilées séparement, à 2-3 exceptions pres, boost::thread en fait partie. pour faciliter la compilation il existe l'utilitaire bjam.
 
edit : ca fait pas trop propagande ? :p


Message édité par blackgoddess le 29-01-2004 à 14:23:21

---------------
-( BlackGoddess )-
Reply

Marsh Posté le 29-01-2004 à 14:23:47    

bien dit. ce qui m'emmerde un peu, c'est que vous comprenez pas ce qu'implique de mixer du C avec du C++ : plus d'expcetion (si y en a une qui parre, c'est le plantage assuré), les destructeur ne sont pas appelés (risque de ne pas libérer des ressources, mais bien plus embêtant que la ram, ne pas libérer un mutex)
 
 
sinon je comprends rien : tu gueules parce qu'il faut passer par une classe, mais c'est toi qui fait une classe
 
 
 
et thread, ça se traduit pas par filament, mais tout simplement par « fil d'exécution »


Message édité par Taz le 29-01-2004 à 14:31:48
Reply

Marsh Posté le 29-01-2004 à 15:07:55    

> thread, ça se traduit pas par filament, mais tout simplement par « fil d'exécution »
 
tu vas un peu vite en besogne. Dans les mensuels (les journaux, quoi, genre LMF, Login, et autres), ca se traduit par "brin", "filament", "fil", et encore d'autres. De la possibilité de pouvoir choisir ... ("tous des cons", c'est ça?)
 
 
pour le reste, je lâche l'affaire...

Reply

Marsh Posté le 29-01-2004 à 15:10:34    

tous des cons. un thread en anglais, dans cet emploi, ne fais pas référence à de la couture ou autre chose, ce qui est important c'est l'exécution

Reply

Marsh Posté le 29-01-2004 à 15:12:15    

arrêtes, tu t'enfonces. ca va finir par se voir.

Reply

Marsh Posté le 29-01-2004 à 19:06:39    

Citation :

le problème n'est pas là. c'est une approche C avec du C++.


 
J'admets que la conception de ma classe Thread n'est pas 'top' (pas non plus 'bottom', enfin j'espere :) ). En outre, il faut reconnaitre également que les appels POSIX sont en pur C...
 
 

Citation :

...au fait, n'utilise pas STL, parce que là t'es à 1% d'utilisation, ça vaut pas la peine


 
Ca m'apprendra a sortir des arguments à la con! Même si seulement 1% de boost me concerne, cela ne devrait pas m'empecher de l'exploiter.  :jap:  
 
 

Citation :

sinon, la plupart des fontionnalités de boost s'ont pas besoin d'être compilées séparement, à 2-3 exceptions pres, boost::thread en fait partie. pour faciliter la compilation il existe l'utilitaire bjam.


 
Effectivement, thread.cpp se compile tout seul (quasiment)! D'ailleurs, je continue d'investiguer le code de Boost::Thread. Par contre, il me jette à la compilation (surement un pb de configuration des .H dédiés à la configuration de la plateforme).
 
 

Citation :

et thread, ça se traduit pas par filament, mais tout simplement par « fil d'exécution »


 
A partir du moment ou tout le monde se comprend, je pense que chacun est libre d'utiliser la traduction qui lui plait le plus plaisir. C'est bien a ça que sert le langage n'est ce pas...
 
Merci pour vos commentaires sur ma classe, je tente de l'améliorer tout en gardant une approche pédagogique.
 
Xter.
 
PS: Et arretez de vous insulter !  :non:  C'est sûr, nous n'avons pas tous le même niveau en programmation... c'est qd même pas bien grave surtout si la volonté de progresser est là !


Message édité par xterminhate le 29-01-2004 à 19:08:10
Reply

Marsh Posté le 29-01-2004 à 19:30:30    

Je persiste à dire qu'utiliser les pthread en C++ de cette manière, c'est aller droit dans le mur. aurevoir

Reply

Marsh Posté le 29-01-2004 à 22:28:22    

Je viens de parcourir un peu plus en détail le code source de boost:thread. C'est un fait : l'"emballage" est nettement mieux fait dans boost.
 
Reste bien assis Taz, parce que sincèrement je ne vois pas de différence fondamentale entre mon code et celui de boost. Ou alors, c'est vraiment subtile! Avant de m'insulter en ligne (sic!), je continue mon investigation, sait-on jamais ;)
 
Cordialement,
   Xter.

Reply

Marsh Posté le 30-01-2004 à 00:06:39    

je suis preneur si tu as un code qui tourne --> PV

Reply

Marsh Posté le 30-01-2004 à 00:32:30    

Je finalise et je te transmets le code.
 
Par ailleurs, je commence à comprendre! Par exemple, un constructeur par recopie n'a aucun sens avec ma classe Thread alors que dans boost::Thread ca marche impec. Cette dernière respecte en effet la conception OO.
 
On va dire que ma classe s'utilise différement...
 
Cordialement,
   Xter.

Reply

Marsh Posté le 30-01-2004 à 01:52:03    

J'en suis arrivé là. Je conserve mon interface (non c++) du début. Je me suis inspiré du code de boost et d'autres librairies. Ca vaut ce que ca vaut. Si vous trouvez un bug, signalez le moi. Merci.
 
Cordialement,
 Xter.
 
 
Les librairies...
 

Code :
  1. // Librairies C++
  2. #include<string>
  3. #include<iostream>
  4. // Librairies supplémentaires  
  5. #ifdef WIN32
  6. #include<process.h>
  7. #else
  8. #include<unistd.h>
  9. #include<pthread.h>
  10. #endif


 
La classe...
 

Code :
  1. // Classe de base filament
  2. class x_Filament
  3. {
  4. public:
  5. // Constructeur
  6. x_Filament();
  7. // Constructeur par recopie
  8. x_Filament( const x_Filament & );
  9. // Destructeur
  10. virtual ~x_Filament();
  11. // Démarre le filament.
  12. void Demarrer();
  13. // Traitement exécuté par le filament
  14. // (A SURCHARGER PAR CLASSE DERIVEE).
  15. virtual void Traitement() = 0;
  16. // Arrète le filament.
  17. void Arreter();
  18. // Attendre la fin du filament.
  19. void Attendre();
  20. // Etat du filament
  21. bool bExecution;
  22. private:
  23. // Filament
  24. #ifdef WIN32
  25. static unsigned __stdcal Filament( void * pthis );
  26. #else
  27. static void * Filament( void * pthis );
  28. #endif
  29. // Identifiants
  30. #ifdef WIN32
  31. HANDLE Identifiant_Filament;
  32. unsigned int Identifiant_Filament_Win32;
  33. #else
  34. pthread_t Identifiant_Filament;
  35. #endif
  36. };


 
Les implémentations....
 

Code :
  1. #ifdef WIN32
  2. unsigned __stdcall x_Filament::Filament( void * pthis ) {
  3. #else
  4. void * x_Filament::Filament( void * pthis ) {
  5. #endif
  6. try
  7. {
  8.  x_Filament * pParent = (x_Filament*)pthis;
  9.  pParent->bExecution = true;
  10.  pParent->Traitement();
  11. }
  12. catch(...)
  13. {
  14. }
  15. #ifdef WIN32
  16. return(0);
  17. //_endthreadex(0);
  18. #else
  19. pthread_exit(0);
  20. #endif
  21. }
  22. x_Filament::x_Filament() : bExecution( false ) { }
  23. x_Filament::~x_Filament() {
  24. if( bExecution )
  25. {
  26.  #ifdef WIN32
  27.  int resultat;
  28.  resultat = CloseHandle( Identifiant_Filament );
  29.  if( resultat == 0 )
  30.   std::cout << std::endl << "Erreur avec CloseHandle()! Error = "  << GetLastError() << "." << std::endl;
  31.  #else
  32.  pthread_detach( Identifiant_Filament );
  33.  #endif
  34. }
  35. }
  36. void x_Filament::Demarrer() {
  37. if( !bExecution )
  38. {
  39.  #ifdef WIN32
  40.  Identifiant_Filament = (HANDLE)_beginthreadex( NULL, 0, &Filament, this, 0, &Identifiant_Filament_Win32 );
  41.  if( Identifiant_Filament == 0 )
  42.   std::cout << std::endl << "Erreur avec _beginthread()!"  << std::endl;
  43.  #else
  44.  int valeur = pthread_create( &Identifiant_Filament, 0, Filament, this );
  45.  if( valeur != 0 )
  46.   std::cout << std::endl << "Erreur avec pthread_create()!"  << std::endl;
  47.  #endif
  48. }
  49. }
  50. void x_Filament::Arreter() {
  51. if( bExecution ) {
  52.  #ifdef WIN32
  53.  TerminateThread( Identifiant_Filament, 0 );
  54.  #else
  55.  pthread_cancel( Identifiant_Filament );
  56.  #endif
  57.  bExecution = false;
  58. }
  59. }
  60. void x_Filament::Attendre() {
  61. if( bExecution ) {
  62.  #ifdef WIN32
  63.  int resultat;
  64.  resultat = WaitForSingleObject( Identifiant_Filament, INFINITE );
  65.  if( resultat != WAIT_OBJECT_0 )
  66.   std::cout << std::endl << "Erreur avec WaitForSingleObject()! Error = " << GetLastError() << "." << std::endl;
  67.  resultat = CloseHandle( Identifiant_Filament );
  68.  if( resultat == 0 )
  69.   std::cout << std::endl << "Erreur avec CloseHandle()! Error = "  << GetLastError() << "." << std::endl;
  70.  #else
  71.  if( pthread_join( Identifiant_Filament, NULL ) != 0 )
  72.   std::cout << std::endl << "Erreur avec pthread_join()!"  << std::endl;
  73.  #endif
  74.  bExecution = false;
  75. }
  76. }


Message édité par xterminhate le 30-01-2004 à 02:13:46
Reply

Marsh Posté le 30-01-2004 à 04:50:05    

Bon j'ai tenté d'ajouter une ptite surcouche C++ à ma classe x_Filament. Je l'appelle x_Filament_Ameliore et elle prend en argument un functor....
 

Code :
  1. template< class foo >
  2. class x_Filament_Ameliore : public x_Filament
  3. {
  4. public:
  5. x_Filament_Ameliore( const foo & f ) : functor(f)
  6. { Demarrer(); }
  7. void Traitement() { functor(); };
  8. private:
  9. const foo & functor;
  10. };


Message édité par xterminhate le 30-01-2004 à 04:58:48
Reply

Marsh Posté le 30-01-2004 à 05:03:17    

Je me demande pourquoi je m'ennuis... je retombe exactement sur boost.... :p

Reply

Marsh Posté le 30-01-2004 à 12:32:53    

En m'inspirant fortement de LMF janvier 2004, voila ce que pourrait donner une adaptation C++ de ma classe thread.
 

Code :
  1. template< class _C, typename _METHODE_TYPE >
  2. class x_Filament_Ameliore : public x_Filament
  3. {
  4. public:
  5. x_Filament_Ameliore( _C* c, void(_C::*m)() )
  6. { Connect(c,m); Demarrer(); }
  7. x_Filament_Ameliore( _C* c, void(_C::*m)() const)
  8. { Connect(c,m); Demarrer(); }
  9. void Traitement() { (in_class->*methode)(); };
  10. private:
  11. void Connect(_C* c, _METHODE_TYPE m)
  12. { in_class = c; methode = m; }
  13. _C* in_class;
  14. _METHODE_TYPE methode;
  15. };


 
Quant à l'utilisation, c'est extremement bourin mais ca permet d'executer en filament n'importe quelle fonction membre de n'importe quelle classe (à condition de la fonction membre retourne void). De ce genre...
 

Code :
  1. class maclasse
  2. {
  3. void operator() () const { /*...*/ }
  4. }


 

Code :
  1. maclasse foo;
  2. x_Filament_Ameliore<maclasse , void (maclasse ::*)() const> fildexecution(&foo, &foo::operator());
  3. // le filament démarre ici et execute de manière concurente la fonction memebre passée en argument : void maclasse()....


 
Cordialement,
   Xter.

Reply

Marsh Posté le 30-01-2004 à 12:47:38    

Je me demande ce qu'il se passe si le destructeur de la classe foo est appelé avant la fin de l'execution du filament( qui execute void foo() )... hum!

Reply

Marsh Posté le 30-01-2004 à 16:38:49    

xterminhate a écrit :

Par exemple, un constructeur par recopie n'a aucun sens avec ma classe Thread alors que dans boost::Thread ca marche impec. Cette dernière respecte en effet la conception OO.


 
bin ... boost::thread hérite de boost::noncopyable, ce qui empêche l'objet d'etre copié, ce qui n'a effectivement aucun sens dans le cas d'un thread :p


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 30-01-2004 à 17:28:35    

Tout a fait, boost empeche l'utilisateur ne faire n'importe quoi avec la classe boost::Thread une fois instanciée... Par curiosité il faudra que je jete un coup d'oeil furtif dans la description de boost:noncopyable histoire de voir comment elle marche. Apparement tu as l'air assez friand de cette classe d'apres ce que j'ai pu constaté :)
 
Merci,
   Xter.
 

Reply

Marsh Posté le 31-01-2004 à 03:40:07    

lool oui, bin c'est pratique je trouve en effet :p
puis elle est super simple cette classe : elle se contente de déclarer le constructeur de copie et l'operateur d'assignation en privée :)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 01-02-2004 à 21:01:34    

Pour en terminer avec ce post, le code source de mon thread c++ est disponible à l'adresse suivante.
 
http://www.cppfrance.com/code.aspx?ID=19908
 
Je ferai probablement des mises à jour pour améliorer ou corriger ce code.
 
Cordialement,
   XteR.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed