[win32 & linux] threads c++

Soyez le premier à donner votre avis sur cette source.

Vue 17 458 fois - Téléchargée 802 fois

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 / Exemple :


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

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Jbs106
Messages postés
21
Date d'inscription
mardi 9 septembre 2003
Statut
Membre
Dernière intervention
5 décembre 2012

C'est juste un soucis d'entete... j'ai tout mis dans un meme fichier dans un certain ordre, it work!
Zakata
Messages postés
59
Date d'inscription
lundi 21 août 2006
Statut
Membre
Dernière intervention
17 juillet 2009

Donne nous les messages d'erreurs que donne le compilateur
Jbs106
Messages postés
21
Date d'inscription
mardi 9 septembre 2003
Statut
Membre
Dernière intervention
5 décembre 2012

Ce source m'interesse mais lors de la compilation, ça boggue. Je suis sous visual c++ 2008. J'ai ouvert un projet console, j'ai bien mis _MT comme option, rien ne change. Pourrai-je avoir un peu d'aide, s'il vous plaît ^^.
Merci
Zakata
Messages postés
59
Date d'inscription
lundi 21 août 2006
Statut
Membre
Dernière intervention
17 juillet 2009

Bonjour,
Merci pour la source ça vas me servir. Je suis d'accord avec toi ; c'est intéressant d'avoir un objet thread.

J'ai une petite remarque :
Le programme de test lève une exception après : "Demande d'arrêt du compteur numéro 3".
J'ai essayé de mettre : monTemps3.Attendre(); après l'arrêt mais sans succès.
J'ai du remplacer un bout de code pour que ça marche : (je me suis passé des exceptions)

#ifdef WIN32

unsigned __stdcall x_Filament::Filament( void * pthis ) {

#else

void * x_Filament::Filament( void * pthis ) {

#endif

//try

if(pthis!=NULL){

x_Filament * pParent = (x_Filament*)pthis;

pParent->bExecution = true;

pParent->Traitement();

}

//catch(...)

//{

//}

#ifdef WIN32

return(0);

//_endthreadex(0);

#else

pthread_exit(0);

#endif

}

Sinon, sais tu combien de thread peux t-on créer dans un soft ?

Pour info la sortie de g++ -v :
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.1-4ubuntu9' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix

gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)
agua2
Messages postés
6
Date d'inscription
jeudi 3 septembre 2009
Statut
Membre
Dernière intervention
10 mars 2010

Merci. Je vais continuer mon développement dans ce sens. Sinon, ton code pour le thread simple, avec les nuances de compil décrites pour VC++6, marche parfaitement bien sûr. Merci aussi pour ça.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.