fonction pthread d’une classe

Disons que j’ai une classe telle que

class c { // ... void *print(void *){ cout << "Hello"; } } 

Et puis j’ai un vecteur de c

 vector classes; pthread_t t1; classes.push_back(c()); classes.push_back(c()); 

Maintenant, je veux créer un thread sur c.print();

Et ce qui suit me donne le problème ci-dessous: pthread_create(&t1, NULL, &c[0].print, NULL);

Error Ouput: impossible de convertir ‘void * (tree_item ::) (void )’ en ‘void * ( ) (void )’ pour l’argument ‘3’ à ‘int pthread_create (pthread_t *, const pthread_attr_t *, void * ( ) (void ), vide *) ‘

Vous ne pouvez pas le faire comme vous l’avez écrit parce que les fonctions membres de la classe C ++ ont un caché. this paramètre a été transmis. pthread_create() n’a aucune idée de la valeur à utiliser, donc si vous essayez de contourner le compilateur la méthode à un pointeur de fonction du type approprié, vous obtiendrez un défaut de segmetnation. Vous devez utiliser une méthode de classe statique (qui ne possède pas this paramètre), ou une simple fonction ordinaire pour amorcer la classe:

 class C { public: void *hello(void) { std::cout << "Hello, world!" << std::endl; return 0; } static void *hello_helper(void *context) { return ((C *)context)->hello(); } }; ... C c; pthread_t t; pthread_create(&t, NULL, &C::hello_helper, &c); 

Ma manière préférée de gérer un thread est de l’encapsuler dans un object C ++. Voici un exemple:

 class MyThreadClass { public: MyThreadClass() {/* empty */} virtual ~MyThreadClass() {/* empty */} /** Returns true if the thread was successfully started, false if there was an error starting the thread */ bool StartInternalThread() { return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0); } /** Will not return until the internal thread has exited. */ void WaitForInternalThreadToExit() { (void) pthread_join(_thread, NULL); } protected: /** Implement this method in your subclass with the code you want your thread to run. */ virtual void InternalThreadEntry() = 0; private: static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;} pthread_t _thread; }; 

Pour l’utiliser, il vous suffit de créer une sous-classe de MyThreadClass avec la méthode InternalThreadEntry () implémentée pour contenir la boucle d’événement de votre thread. Vous devez appeler WaitForInternalThreadToExit () sur l’object thread avant de supprimer l’object thread, bien sûr (et avoir un mécanisme pour vous assurer que le thread se ferme réellement, sinon WaitForInternalThreadToExit () ne reviendra jamais)

Vous devrez donner à pthread_create une fonction correspondant à la signature recherchée. Ce que vous passez ne marchera pas.

Vous pouvez implémenter n’importe quelle fonction statique que vous aimez faire, et il peut référencer une instance de c et exécuter ce que vous voulez dans le thread. pthread_create est conçu pour prendre non seulement un pointeur de fonction, mais aussi un pointeur sur “contexte”. Dans ce cas, vous passez simplement un pointeur sur une instance de c .

Par exemple:

 static void* execute_print(void* ctx) { c* cptr = (c*)ctx; cptr->print(); return NULL; } void func() { ... pthread_create(&t1, NULL, execute_print, &c[0]); ... } 

Les réponses ci-dessus sont bonnes, mais dans mon cas, la 1ère approche qui convertit la fonction en statique ne fonctionne pas. J’essayais de convertir le code existant pour passer dans la fonction thread mais ce code avait déjà beaucoup de références aux membres non statiques de la classe. La deuxième solution d’encapsulation dans un object C ++ fonctionne, mais comporte des wrappers à trois niveaux pour exécuter un thread.

J’avais une solution alternative qui utilise la construction C ++ existante – la fonction «ami» et cela fonctionnait parfaitement pour mon cas. Un exemple de la façon dont j’ai utilisé «ami» (utilisera le même exemple ci-dessus pour les noms montrant comment il peut être converti en une forme compacte en utilisant un ami)

  class MyThreadClass { public: MyThreadClass() {/* empty */} virtual ~MyThreadClass() {/* empty */} bool Init() { return (pthread_create(&_thread, NULL, &ThreadEntryFunc, this) == 0); } /** Will not return until the internal thread has exited. */ void WaitForThreadToExit() { (void) pthread_join(_thread, NULL); } private: //our friend function that runs the thread task friend void* ThreadEntryFunc(void *); pthread_t _thread; }; //friend is defined outside of class and without any qualifiers void* ThreadEntryFunc(void *obj_param) { MyThreadClass *thr = ((MyThreadClass *)obj_param); //access all the members using thr-> return NULL; } 

Bien sûr, nous pouvons utiliser boost :: thread et éviter tout cela, mais j’essayais de modifier le code C ++ pour ne pas utiliser boost (le code était lié à boost uniquement à cette fin)

Ma première réponse dans l’espoir que ce sera utile à quelqu’un: c’est une vieille question, mais j’ai rencontré exactement la même erreur que la question précédente, car j’écris une classe TcpServer et j’essayais d’utiliser pthreads. J’ai trouvé cette question et je comprends maintenant pourquoi cela se passait. J’ai fini par faire ça:

 #include  

méthode pour exécuter threaded -> void* TcpServer::sockethandler(void* lp) {/*code here*/}

et je l’appelle avec un lambda -> std::thread( [=] { sockethandler((void*)csock); } ).detach();

cela me semble une approche propre.

Trop souvent, j’ai trouvé le moyen de résoudre ce que vous demandiez, à mon avis, c’est trop compliqué. Par exemple, vous devez définir de nouveaux types de classes, une bibliothèque de liens, etc. J’ai donc décidé d’écrire quelques lignes de code qui permettent à l’utilisateur final de “mettre en forme” un “void :: method (void)” de quelle que soit la classe. Bien sûr, cette solution que j’ai implémentée peut être étendue, améliorée, etc. Ainsi, si vous avez besoin de méthodes ou de fonctionnalités plus spécifiques, ajoutez-les et soyez gentil de me tenir au courant.

Voici 3 fichiers qui montrent ce que j’ai fait.

  // A basic mutex class, I called this file Mutex.h #ifndef MUTEXCONDITION_H_ #define MUTEXCONDITION_H_ #include  #include  class MutexCondition { private: bool init() { //printf("MutexCondition::init called\n"); pthread_mutex_init(&m_mut, NULL); pthread_cond_init(&m_con, NULL); return true; } bool destroy() { pthread_mutex_destroy(&m_mut); pthread_cond_destroy(&m_con); return true; } public: pthread_mutex_t m_mut; pthread_cond_t m_con; MutexCondition() { init(); } virtual ~MutexCondition() { destroy(); } bool lock() { pthread_mutex_lock(&m_mut); return true; } bool unlock() { pthread_mutex_unlock(&m_mut); return true; } bool wait() { lock(); pthread_cond_wait(&m_con, &m_mut); unlock(); return true; } bool signal() { pthread_cond_signal(&m_con); return true; } }; #endif // End of Mutex.h 

// La classe qui encapsule tout le travail pour filer une méthode (test.h):

 #ifndef __THREAD_HANDLER___ #define __THREAD_HANDLER___ #include  #include  #include  #include "Mutex.h" using namespace std; template  class CThreadInfo { public: typedef void (T::*MHT_PTR) (void); vector _threaded_methods; vector _status_flags; T *_data; MutexCondition _mutex; int _idx; bool _status; CThreadInfo(T* p1):_data(p1), _idx(0) {} void setThreadedMethods(vector & pThreadedMethods) { _threaded_methods = pThreadedMethods; _status_flags.resize(_threaded_methods.size(), false); } }; template  class CSThread { protected: typedef void (T::*MHT_PTR) (void); vector _threaded_methods; vector _thread_labels; MHT_PTR _stop_f_pt; vector _elements; vector _performDelete; vector*> _threadlds; vector _threads; int _totalRunningThreads; static void * gencker_(void * pArg) { CThreadInfo* vArg = (CThreadInfo *) pArg; vArg->_mutex.lock(); int vIndex = vArg->_idx++; vArg->_mutex.unlock(); vArg->_status_flags[vIndex]=true; MHT_PTR mhtCalledOne = vArg->_threaded_methods[vIndex]; (vArg->_data->*mhtCalledOne)(); vArg->_status_flags[vIndex]=false; return NULL; } public: CSThread ():_stop_f_pt(NULL), _totalRunningThreads(0) {} ~CSThread() { for (int i=_threads.size() -1; i >= 0; --i) pthread_detach(*_threads[i]); for (int i=_threadlds.size() -1; i >= 0; --i) delete _threadlds[i]; for (int i=_elements.size() -1; i >= 0; --i) if (find (_performDelete.begin(), _performDelete.end(), _elements[i]) != _performDelete.end()) delete _elements[i]; } int runningThreadsCount(void) {return _totalRunningThreads;} int elementsCount() {return _elements.size();} void addThread (MHT_PTR p, ssortingng pLabel="") { _threaded_methods.push_back(p); _thread_labels.push_back(pLabel);} void clearThreadedMethods() { _threaded_methods.clear(); } void getThreadedMethodsCount() { return _threaded_methods.size(); } void addStopMethod(MHT_PTR p) { _stop_f_pt = p; } ssortingng getStatusStr(unsigned int _elementIndex, unsigned int pMethodIndex) { char ch[99]; if (getStatus(_elementIndex, pMethodIndex) == true) sprintf (ch, "[%s] - TRUE\n", _thread_labels[pMethodIndex].c_str()); else sprintf (ch, "[%s] - FALSE\n", _thread_labels[pMethodIndex].c_str()); return ch; } bool getStatus(unsigned int _elementIndex, unsigned int pMethodIndex) { if (_elementIndex > _elements.size()) return false; return _threadlds[_elementIndex]->_status_flags[pMethodIndex]; } bool run(unsigned int pIdx) { T * myElem = _elements[pIdx]; _threadlds.push_back(new CThreadInfo(myElem)); _threadlds[_threadlds.size()-1]->setThreadedMethods(_threaded_methods); int vStart = _threads.size(); for (int hhh=0; hhh<_threaded_methods.size(); ++hhh) _threads.push_back(new pthread_t); for (int currentCount =0; currentCount < _threaded_methods.size(); ++vStart, ++currentCount) { if (pthread_create(_threads[vStart], NULL, gencker_, (void*) _threadlds[_threadlds.size()-1]) != 0) { // cout <<"\t\tThread " << currentCount << " creation FAILED for element: " << pIdx << endl; return false; } else { ++_totalRunningThreads; // cout <<"\t\tThread " << currentCount << " creation SUCCEDED for element: " << pIdx << endl; } } return true; } bool run() { for (int vI = 0; vI < _elements.size(); ++vI) if (run(vI) == false) return false; // cout <<"Number of currently running threads: " << _totalRunningThreads << endl; return true; } T * addElement(void) { int vId=-1; return addElement(vId); } T * addElement(int & pIdx) { T * myElem = new T(); _elements.push_back(myElem); pIdx = _elements.size()-1; _performDelete.push_back(myElem); return _elements[pIdx]; } T * addElement(T *pElem) { int vId=-1; return addElement(pElem, vId); } T * addElement(T *pElem, int & pIdx) { _elements.push_back(pElem); pIdx = _elements.size()-1; return pElem; } T * getElement(int pId) { return _elements[pId]; } void stopThread(int i) { if (_stop_f_pt != NULL) { ( _elements[i]->*_stop_f_pt)() ; } pthread_detach(*_threads[i]); --_totalRunningThreads; } void stopAll() { if (_stop_f_pt != NULL) for (int i=0; i<_elements.size(); ++i) { ( _elements[i]->*_stop_f_pt)() ; } _totalRunningThreads=0; } }; #endif // end of test.h 

// Un fichier d’exemple d’utilisation “test.cc” que j’ai compilé avec Linux avec la classe qui incorpore tout le travail pour convertir une méthode en thread: g ++ -o mytest.exe test.cc -I. -lpthread -lstdc ++

 #include  #include  #include  #include  using namespace std; // Just a class for which I need to "thread-ize" a some methods // Given that with OOP the objecs include both "functions" (methods) // and data (atsortingbutes), then there is no need to use function arguments, // just a "void xxx (void)" method. // class TPuck { public: bool _go; TPuck(int pVal):_go(true) { Value = pVal; } TPuck():_go(true) { } int Value; int vc; void setValue(int p){Value = p; } void super() { while (_go) { cout <<"super " << vc << endl; sleep(2); } cout <<"end of super " << vc << endl; } void vusss() { while (_go) { cout <<"vusss " << vc << endl; sleep(2); } cout <<"end of vusss " << vc << endl; } void fazz() { static int vcount =0; vc = vcount++; cout <<"Puck create instance: " << vc << endl; while (_go) { cout <<"fazz " << vc << endl; sleep(2); } cout <<"Completed TPuck..fazz instance "<< vc << endl; } void stop() { _go=false; cout << endl << "Stopping TPuck...." << vc << endl; } }; int main(int argc, char* argv[]) { // just a number of instances of the class I need to make threads int vN = 3; // This object will be your threads maker. // Just declare an instance for each class // you need to create method threads // CSThread PuckThreadMaker; // // Hera I'm telling which methods should be threaded PuckThreadMaker.addThread(&TPuck::fazz, "fazz1"); PuckThreadMaker.addThread(&TPuck::fazz, "fazz2"); PuckThreadMaker.addThread(&TPuck::fazz, "fazz3"); PuckThreadMaker.addThread(&TPuck::vusss, "vusss"); PuckThreadMaker.addThread(&TPuck::super, "super"); PuckThreadMaker.addStopMethod(&TPuck::stop); for (int ii=0; ii 

J’imagine que c / b est un peu bombardé par C ++ si vous lui envoyez un pointeur C ++, pas un pointeur de fonction C. Il y a une différence apparemment. Essayez de faire un

 (void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast) 

puis envoi p.

J’ai fait ce que vous faites avec une fonction membre, mais je l’ai fait dans la classe qui l’utilisait, et avec une fonction statique – ce qui, à mon avis, a fait la différence.

C ++: Comment passer la fonction membre de classe à pthread_create ()?

http://thispointer.com/c-how-to-pass-class-member-function-to-pthread_create/

 typedef void * (*THREADFUNCPTR)(void *); class C { // ... void *print(void *) { cout << "Hello"; } } pthread_create(&threadId, NULL, (THREADFUNCPTR) &C::print, NULL);