Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

[WIN32 & LINUX] THREADS C++


Information sur la source

Catégorie :Système Niveau : Initié Date de création : 30/01/2004 Date de mise à jour : 30/01/2004 23:02:46 Vu / téléchargé: 11 198 / 667

Note :
9,83 / 10 - par 6 personnes
9,83 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (16)
Ajouter un commentaire et/ou une note

Description

Il s'agit d'un classe qui encapsule l'execution d'un thread Win32/POSIX.

Cette classe offre à l'utilisateur une interface de haut niveau pour contrôler l'execution du thread (démarrer, arreter, attendre, ...).

Un programme d'exemple est fourni avec le source thread.h/.cpp pour guider l'utilisateur dans l'utilisation de cette classe.

Ce source compile sous Win32 et sous GNU/Linux (ne pas oublier de linker avec pthread.lib sous Linux).

Il y a deux moyens d'exploiter cette classe :

1) créer une classe qui dérive de "Filament" et qui surcharge la fonction membre "void Filament::Traitement()". L'exécution du thread est controlée par Filament::Demarrer(), ::Arreter(), Attendre().

2) créer une classe quelconque ("foo" pour l'exemple) contenant une fonction membre quelconque ("void foo:operator()()" pour l'exemple). Instancier alors la classe quelconque ("foo_inst" pour l'exemple) puis la classe "Filament_Avance" avec pour argument (dans le constructeur) les adresses de la classe et de la fonction membre : Filament_Avance<foo> monfil(&foo_inst, void &foo::operator()). Le thread démarre immédiate et execute le contenu de foo:operator().

Bonne chance...
Xter.

 

Source

  • // Librairies C++
  • #include<string>
  • #include<iostream>
  • // Librairies supplémentaires
  • #ifdef WIN32
  • #include<process.h>
  • #else
  • #include<unistd.h>
  • #include<pthread.h>
  • #endif
  • // Classe de base filament
  • class x_Filament
  • {
  • public:
  • // Constructeur
  • x_Filament();
  • // Constructeur par recopie
  • x_Filament( const x_Filament & );
  • /// Destructeur
  • virtual ~x_Filament();
  • // Démarre le filament.
  • void Demarrer();
  • // Traitement exécuté par le filament.
  • virtual void Traitement() = 0;
  • // Arrète le filament.
  • void Arreter();
  • // Attendre la fin du filament.
  • void Attendre();
  • // Etat du filament
  • bool bExecution;
  • private:
  • // Filament
  • #ifdef WIN32
  • static unsigned __stdcall Filament( void * pthis );
  • #else
  • static void * Filament( void * pthis );
  • #endif
  • // Identifiants
  • #ifdef WIN32
  • HANDLE Identifiant_Filament;
  • unsigned int Identifiant_Filament_Win32;
  • #else
  • pthread_t Identifiant_Filament;
  • #endif
  • };
  • // Classe derivée filament "amelioré"
  • template< class T_CLASSE >
  • class x_Filament_Ameliore : public x_Filament
  • {
  • public:
  • // Constructeurs : l'un pour les fonctions membres normales, l'autre pour les fonctions membres 'const'
  • x_Filament_Ameliore( T_CLASSE * c, void (T_CLASSE::*m)() );
  • x_Filament_Ameliore( T_CLASSE * c, void (T_CLASSE::*m)() const );
  • // Traitement exécuté par le filament : execute l'instruction (classe->*methode)()
  • void Traitement();
  • private:
  • // Adresses de la classe
  • T_CLASSE * classe;
  • // Adresse de la méthode
  • void (T_CLASSE::*methode_normale) ();
  • void (T_CLASSE::*methode_const) () const;
  • // Type de méthode
  • const bool bConst;
  • };
  • template < class _CLASSE >
  • x_Filament_Ameliore< _CLASSE >::x_Filament_Ameliore( _CLASSE * c, void(_CLASSE::*m)() ) :
  • bConst(false)
  • {
  • classe = c;
  • methode_normale = m;
  • Demarrer();
  • }
  • template < class _CLASSE >
  • x_Filament_Ameliore< _CLASSE >::x_Filament_Ameliore( _CLASSE * c, void(_CLASSE::*m)() const ) :
  • bConst(true)
  • {
  • classe = c;
  • methode_const = m;
  • Demarrer();
  • }
  • template < class _CLASSE >
  • void x_Filament_Ameliore<_CLASSE >::Traitement() {
  • if( bConst )
  • (classe->*methode_const)();
  • else
  • (classe->*methode_normale)();
  • }
  • #ifdef WIN32
  • unsigned __stdcall x_Filament::Filament( void * pthis ) {
  • #else
  • void * x_Filament::Filament( void * pthis ) {
  • #endif
  • try
  • {
  • x_Filament * pParent = (x_Filament*)pthis;
  • pParent->bExecution = true;
  • pParent->Traitement();
  • }
  • catch(...)
  • {
  • }
  • #ifdef WIN32
  • return(0);
  • //_endthreadex(0);
  • #else
  • pthread_exit(0);
  • #endif
  • }
  • x_Filament::x_Filament() : bExecution( false ) { }
  • x_Filament::~x_Filament() {
  • if( bExecution )
  • {
  • #ifdef WIN32
  • int resultat;
  • resultat = CloseHandle( Identifiant_Filament );
  • if( resultat == 0 )
  • std::cout << std::endl << "Erreur avec CloseHandle()! Error = " << GetLastError() << "." << std::endl;
  • #else
  • pthread_detach( Identifiant_Filament );
  • #endif
  • }
  • }
  • void x_Filament::Demarrer() {
  • if( !bExecution )
  • {
  • #ifdef WIN32
  • Identifiant_Filament = (HANDLE)_beginthreadex( NULL, 0, &Filament, this, 0, &Identifiant_Filament_Win32 );
  • if( Identifiant_Filament == 0 )
  • std::cout << std::endl << "Erreur avec _beginthread()!" << std::endl;
  • #else
  • int valeur = pthread_create( &Identifiant_Filament, 0, Filament, this );
  • if( valeur != 0 )
  • std::cout << std::endl << "Erreur avec pthread_create()!" << std::endl;
  • #endif
  • }
  • }
  • void x_Filament::Arreter() {
  • if( bExecution ) {
  • #ifdef WIN32
  • TerminateThread( Identifiant_Filament, 0 );
  • #else
  • pthread_cancel( Identifiant_Filament );
  • #endif
  • bExecution = false;
  • }
  • }
  • void x_Filament::Attendre() {
  • if( bExecution ) {
  • #ifdef WIN32
  • int resultat;
  • resultat = WaitForSingleObject( Identifiant_Filament, INFINITE );
  • if( resultat != WAIT_OBJECT_0 )
  • std::cout << std::endl << "Erreur avec WaitForSingleObject()! Error = " << GetLastError() << "." << std::endl;
  • resultat = CloseHandle( Identifiant_Filament );
  • if( resultat == 0 )
  • std::cout << std::endl << "Erreur avec CloseHandle()! Error = " << GetLastError() << "." << std::endl;
  • #else
  • if( pthread_join( Identifiant_Filament, NULL ) != 0 )
  • std::cout << std::endl << "Erreur avec pthread_join()!" << std::endl;
  • #endif
  • bExecution = false;
  • }
  • }
// Librairies C++
#include<string>
#include<iostream>

// Librairies supplémentaires 
#ifdef WIN32
	#include<process.h>
#else
	#include<unistd.h>
    #include<pthread.h>
#endif

// Classe de base filament
class x_Filament 
{
public:
		
	// Constructeur
	x_Filament();
		
	// Constructeur par recopie
	x_Filament( const x_Filament & );
		
	/// Destructeur
	virtual ~x_Filament();
		
	// Démarre le filament.
    void Demarrer();
		
	// Traitement exécuté par le filament.
	virtual void Traitement() = 0;
		
	// Arrète le filament.
    void Arreter();
		
	// Attendre la fin du filament.
    void Attendre();
		
	// Etat du filament
	bool bExecution;
		
private:
		
	// Filament
	#ifdef WIN32
	static unsigned __stdcall Filament( void * pthis );
	#else
	static void * Filament( void * pthis );
	#endif
		
	// Identifiants
	#ifdef WIN32
	HANDLE Identifiant_Filament;
	unsigned int Identifiant_Filament_Win32;
	#else
	pthread_t Identifiant_Filament;
	#endif
};

// Classe derivée filament "amelioré"
template< class T_CLASSE >
class x_Filament_Ameliore : public x_Filament
{
public:
		
	// Constructeurs : l'un pour les fonctions membres normales, l'autre pour les fonctions membres 'const'	
	x_Filament_Ameliore( T_CLASSE * c, void (T_CLASSE::*m)() );
	x_Filament_Ameliore( T_CLASSE * c, void (T_CLASSE::*m)() const );
	
	// Traitement exécuté par le filament : execute l'instruction (classe->*methode)()
	void Traitement();
		
private:
		
	// Adresses de la classe
	T_CLASSE * classe;
		
	// Adresse de la méthode
	void (T_CLASSE::*methode_normale) ();
	void (T_CLASSE::*methode_const) () const;
		
	// Type de méthode
	const bool bConst;
};

template < class _CLASSE >
x_Filament_Ameliore< _CLASSE >::x_Filament_Ameliore( _CLASSE * c, void(_CLASSE::*m)() ) :
bConst(false)
{
	classe = c;
	methode_normale = m;
	Demarrer();
}

template < class _CLASSE >
x_Filament_Ameliore< _CLASSE >::x_Filament_Ameliore( _CLASSE * c, void(_CLASSE::*m)() const ) :
bConst(true)
{
	classe = c;
	methode_const = m;
	Demarrer();
}

template < class _CLASSE >
void x_Filament_Ameliore<_CLASSE >::Traitement() {
	if( bConst )
		(classe->*methode_const)();
	else
		(classe->*methode_normale)();
}

#ifdef WIN32
unsigned __stdcall x_Filament::Filament( void * pthis ) {
#else
void * x_Filament::Filament( void * pthis ) {
#endif
	try
	{			
		x_Filament * pParent = (x_Filament*)pthis;
		pParent->bExecution = true;
		pParent->Traitement();
	}
	catch(...)
	{
	}
	#ifdef WIN32
	return(0);
	//_endthreadex(0);
	#else
	pthread_exit(0);
	#endif
}

x_Filament::x_Filament() : bExecution( false ) { }

x_Filament::~x_Filament() {
	if( bExecution )
	{
		#ifdef WIN32
		int resultat;
		resultat = CloseHandle( Identifiant_Filament );
		if( resultat == 0 )
			std::cout << std::endl << "Erreur avec CloseHandle()! Error = "  << GetLastError() << "." << std::endl;
		#else
		pthread_detach( Identifiant_Filament );
		#endif
	}
}

void x_Filament::Demarrer() {
	if( !bExecution ) 
	{
		#ifdef WIN32
		Identifiant_Filament = (HANDLE)_beginthreadex( NULL, 0, &Filament, this, 0, &Identifiant_Filament_Win32 );
		if( Identifiant_Filament == 0 )
			std::cout << std::endl << "Erreur avec _beginthread()!"  << std::endl;
		#else
		int valeur = pthread_create( &Identifiant_Filament, 0, Filament, this );
		if( valeur != 0 )
			std::cout << std::endl << "Erreur avec pthread_create()!"  << std::endl;
		#endif
	}
}

void x_Filament::Arreter() {
	if( bExecution ) {
		#ifdef WIN32
		TerminateThread( Identifiant_Filament, 0 );		
		#else
		pthread_cancel( Identifiant_Filament );
		#endif
		bExecution = false;
	}
}

void x_Filament::Attendre() {
	if( bExecution ) {
		#ifdef WIN32
		int resultat;
		resultat = WaitForSingleObject( Identifiant_Filament, INFINITE );
		if( resultat != WAIT_OBJECT_0 )
			std::cout << std::endl << "Erreur avec WaitForSingleObject()! Error = " << GetLastError() << "." << std::endl;
		resultat = CloseHandle( Identifiant_Filament );
		if( resultat == 0 )
			std::cout << std::endl << "Erreur avec CloseHandle()! Error = "  << GetLastError() << "." << std::endl;
		#else
		if( pthread_join( Identifiant_Filament, NULL ) != 0 )
			std::cout << std::endl << "Erreur avec pthread_join()!"  << std::endl;
		#endif
		bExecution = false;
	}		
}


Conclusion

Bug connu : Ne pas appeler filament::attendre() juste apres filament::demarrer(), faire une pause sinon le thread à même pas le temps de se lancer et donc l'identifiant du thread n'est pas positioné.
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Commentaires et avis

signaler à un administrateur
Commentaire de BruNews le 30/01/2004 19:52:18 administrateur CS

Salut,
d'abord bravo pour le travail.
Mais enfin c'est le but qui m'echappe. Pourquoi faire complique quand l'original est simple, je parle pour win32 seulement ?

signaler à un administrateur
Commentaire de xterminhate le 30/01/2004 20:01:20

Merci ... et bonne question :)

L'idée est d'avoir une même interface (une même classe thread) pour Win32 et GNU/Linux. Une interface de haut niveau au passage et si possible orienté objet (enfin presque...taz si tu m'ecoutes? pardon!).

D'autre part, cela améliore un peu la lisibilité du code puisque les appels des threads et la gestion des identifiants de threads devient transparente.

Enfin, cette classe offre au débutant la possibilité de créer des threads rapidement sans même connaitre la syntaxe des appels posix ou win32. Enfin, attention qd même les classe dérivées de ma classe Filament ne sont pas automatiquement "thread safe" bien sur!

Et puis je suis en RTT depuis hier alors fallait que je m'occupe :)

Cordialement,
   Xter!

signaler à un administrateur
Commentaire de eracius le 26/12/2004 19:31:09

salut à toi et merci pour cette classe, c exactement ce qu'il me fallait.
Seulement voila, je dois etre un gros boulet mais j'arrive po à m'en servir.
j'ai mis ceci :
x_Filament_Ameliore<vehicule> monfil(&clio, void &vehicule::avance() );
Et il dit "parse error before "&" token"
alors j'enlève le & devant vehicule et il met :
"parse error before "::" token"

vois-tu le problème ? merci :)

signaler à un administrateur
Commentaire de xterminhate le 26/12/2004 19:44:34

Et cà ?
x_Filament_Ameliore<vehicule> monfil(&clio, &vehicule::avance );

signaler à un administrateur
Commentaire de worms4 le 08/03/2006 12:44:52

Je comprend essensielment bien le but de ta classe et c'est pour cela que je la trouve très très interessente mais si tu pouvais rajouter quelque exemple pour bien comprendre l'utilisation de chacune de tes fonction je t'en serais grandement reconnaissent.

Et bonne RTT

signaler à un administrateur
Commentaire de Ange44 le 16/08/2006 11:31:57

Salut !

J'ai mis du temps à trouver mais grace à ta classe j'ai enfin trouvé une interface simple pour faire des threads portables !

Par contre  j'ai un petit problème, quand j'essaye de compiler ton programme sous VS 2003 .NET il me dit qu'il ne connait pas HANDLE (et d'autres trucs). Y a-t-il des includes supplémentaires à ajouter ?

Sinon je ne compte utiliser que les x_Filament_Ameliore mais il plante au linkage dans mon code car il n'a pas le code (vu qu'il arrive à  compiler tes sources :( )

Si tu as une idée ?

signaler à un administrateur
Commentaire de xterminhate le 16/08/2006 12:36:15

Tu devrais passer sous VS8 Express qui est gratuit.

Il me semble que HANDLE appartient à windows.h. Compile/Link en multi-thread.

Le code doit se trouver dans un .h qui est "includé" dans chaque source qui utilise mes classes. L'Export Template n'est pas d'actualité.


Des exemples sont fournis avec le source (main.cpp).

Bonne chance.



signaler à un administrateur
Commentaire de Ange44 le 16/08/2006 13:43:40

Merci, mais en fait j'avais trouvé il me fallait compiler en MultiThread en effet ;)

Sinon je dois rester sous VS 2003 .NET à cause de biblliothèques que j'utilise (développées en interne, et pour le moment non compatible avec VS supérieur à 2003 .NET :() Enfin ça ne m'empêche pas de bosser ;)

signaler à un administrateur
Commentaire de cyfive le 04/01/2007 06:03:53

Bravo pour ces 2 classes. Ca faisait longtemps que je cherchais comment faire des thread sous windows avec DevCPP. Un grand merci. J'ai une recommendation à faire: est-ce que tu pourrais ajouter des méthodes à ta classe de base afin que l'on puisse faire une pause à notre thread et ensuite une autre pour continuer la thread. J'ai vu ça avec la VCL de Borland et je trouverais ça interressant.

Autre chose, je trouve ta convention de nommage pas très claire. Pour faciliter la compréhension j'ai du traduire tes 2 classes.
En tout cas chacun sa convention. :)

signaler à un administrateur
Commentaire de xterminhate le 05/02/2007 23:59:39

Bonjour, merci pour ce commentaire.

En relisant le code, je trouve effectivement que la notation est perfectible.

Pour la pause, j'avoue ne pas avoir le temps de rafraichir le source. Sais tu t'en occcuper ?

Merci.

signaler à un administrateur
Commentaire de wadcyr8_197 le 16/07/2007 13:43:47

Salut,
merci bien pour cette petite classe c'est exactement ce qu'il me fallait. Seulement j'ai quelques problème à l'utilisation. Lorsque je mets ceci :
x_Filament_Ameliore<Telnet> fil_telnet(&connexion_telnet, void &Telnet::initialization() );

c'est comme ce que faisait ERACIUS, j'obtiens une erreur différence de la sienne :
error: expected primary-expression before "void"

si je mets ta correction à son problème :
x_Filament_Ameliore<Telnet> fil_telnet(&connexion_telnet, &Telnet::initialization );

j'obtiens :
error: no matching function for call to `x_Filament_Ameliore<Telnet>::x_Filament_Ameliore(Telnet*, void (*)())'

là je comprends ce qui ne lui plait pas, mais je ne vois pas où est l'erreur ?
si quelqu'un peut m'aider

merci d'avance

signaler à un administrateur
Commentaire de crunch117 le 19/07/2007 17:30:23

Regarde bien si ta fonction Telnet::initialization possède ce prototype dans la déclaration de ta classe :

    void initialization();

++

signaler à un administrateur
Commentaire de wadcyr8_197 le 20/07/2007 10:15:58

merci, mais c'est pas ça, en fait je viens de trouver, c'est juste que j'avais un static qui trainait d'une part à la déclaration de ma fonction et ensuite il n'aime pas les constructeurs qui ont besoin d'argument :d

signaler à un administrateur
Commentaire de wadcyr8_197 le 25/07/2007 11:29:26

Salut,
je suis confronté à un nouveau problème avec l'utilisation des threads !
j'ai un prog main qui se charge de lancer 2 threads et de se met en sleep derrière.
Le premier thread ouvre une connexion telnet pour passer des instructions à une machine distante de façon à ce qu'elle envoie des info sur une socket particulière, le deuxième thread écoute sur cette socket et récupère des messages xml dessus, le troisième récupère ces messages xml et les parse.
j'ai un petit problème quand mon main quitte sont sleep, il se termine (normal) et provoque la fin de mes threads (normal aussi), le truc c'est qu'il me provoque un crash de mon troisième.
je n'arrive pas à utiliser gdb pour voir exactement où se situe le problème et de quel type il s'agit, mais avec des cout, j'ai pu voir que c'était à la fin de mon main et lorsque mon thread parseur s'apprète à faire un découpage que ça merde.

si quelqu'un peut m'aider

merci bien
Wad

ps : je précise que j'utilise codeblocks sous windows

signaler à un administrateur
Commentaire de Helldream le 07/11/2007 01:14:47

Je cherchais une classe de ce genre pour m'en inspirer, et visiblement je l'ai trouvée :)

Merci pour ton apport!

signaler à un administrateur
Commentaire de ordiman85 le 07/06/2008 11:59:18 10/10

Super bon boulot je te mets 10/10, je vais de plus utiliser ta source, merci

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Décembre 2008
LMMJVSD
1234567
891011121314
15161718192021
22232425262728
293031    

Consulter la suite du CalendriCode



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel BAÏSE, Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,234 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.