Digamos que tengo una clase como
class c {
// ...
void *print(void *){ cout << "Hello"; }
}
Y luego tengo un vector de c
vector<c> classes; pthread_t t1;
classes.push_back(c());
classes.push_back(c());
Ahora, quiero crear un hilo en c.print();
Y lo siguiente me está dando el siguiente problema: pthread_create(&t1, NULL, &c[0].print, NULL);
Error Ouput: no se puede convertir 'void * (tree_item ::) (void )' a 'void * ( ) (void )' para el argumento '3' a 'int pthread_create (pthread_t *, const pthread_attr_t *, void * ( ) (void ), nulo *) '
Mi forma favorita de manejar un hilo es encapsularlo dentro de un objeto C ++. He aquí un ejemplo:
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; };
Para usarlo, simplemente crearía una subclase de MyThreadClass con el método InternalThreadEntry () implementado para contener el ciclo de eventos de su hilo. Debería llamar a WaitForInternalThreadToSalir () en el objeto hilo antes de eliminar el objeto hilo, por supuesto (y tener algún mecanismo para asegurarse de que el hilo realmente salga, de lo contrario WaitForInternalThreadToSalir () nunca volvería)
fuente
Deberá asignar
pthread_create
una función que coincida con la firma que está buscando. Lo que estás pasando no funcionará.Puede implementar cualquier función estática que desee para hacer esto, y puede hacer referencia a una instancia
c
y ejecutar lo que desee en el hilo.pthread_create
está diseñado para tomar no solo un puntero de función, sino también un puntero al "contexto". En este caso, simplemente le pasa un puntero a una instancia dec
.Por ejemplo:
static void* execute_print(void* ctx) { c* cptr = (c*)ctx; cptr->print(); return NULL; } void func() { ... pthread_create(&t1, NULL, execute_print, &c[0]); ... }
fuente
Las respuestas anteriores son buenas, pero en mi caso, el primer enfoque que convierte la función en estática no funcionó. Estaba tratando de convertir el código existente para pasar a la función de subproceso, pero ese código ya tenía muchas referencias a miembros de clase no estáticos. La segunda solución de encapsular en un objeto C ++ funciona, pero tiene envoltorios de 3 niveles para ejecutar un hilo.
Tenía una solución alternativa que usa la construcción C ++ existente - función 'amigo', y funcionó perfectamente para mi caso. Un ejemplo de cómo usé 'amigo' (usaré el mismo ejemplo anterior para los nombres que muestran cómo se puede convertir en una forma compacta usando amigo)
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; }
Por supuesto, podemos usar boost :: thread y evitar todo esto, pero estaba tratando de modificar el código C ++ para no usar boost (el código se vinculaba con boost solo para este propósito)
fuente
Mi primera respuesta con la esperanza de que sea útil para alguien: ahora, esta es una pregunta antigua, pero encontré exactamente el mismo error que la pregunta anterior mientras escribía una clase TcpServer y estaba tratando de usar pthreads. Encontré esta pregunta y ahora entiendo por qué estaba sucediendo. Terminé haciendo esto:
#include <thread>
método para ejecutar roscado ->
void* TcpServer::sockethandler(void* lp) {/*code here*/}
y lo llamo con una lambda ->
std::thread( [=] { sockethandler((void*)csock); } ).detach();
eso me parece un enfoque limpio.
fuente
Demasiadas veces he encontrado formas de solucionar lo que me pides que, en mi opinión son demasiado complicadas. Por ejemplo, tienes que definir nuevos tipos de clases, biblioteca de enlaces, etc. Así que decidí escribir algunas líneas de código que permitan al usuario final básicamente poder "crear hilos" en un "método void :: (void)" de cualquier clase. Seguro que esta solución que implementé se puede ampliar, mejorar, etc., así que, si necesita métodos o funciones más específicos, agréguelos y sea tan amable de mantenerme informado.
Aquí hay 3 archivos que muestran lo que hice.
// A basic mutex class, I called this file Mutex.h #ifndef MUTEXCONDITION_H_ #define MUTEXCONDITION_H_ #include <pthread.h> #include <stdio.h> 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 clase que encapsula todo el trabajo para procesar un método (test.h):
#ifndef __THREAD_HANDLER___ #define __THREAD_HANDLER___ #include <pthread.h> #include <vector> #include <iostream> #include "Mutex.h" using namespace std; template <class T> class CThreadInfo { public: typedef void (T::*MHT_PTR) (void); vector<MHT_PTR> _threaded_methods; vector<bool> _status_flags; T *_data; MutexCondition _mutex; int _idx; bool _status; CThreadInfo(T* p1):_data(p1), _idx(0) {} void setThreadedMethods(vector<MHT_PTR> & pThreadedMethods) { _threaded_methods = pThreadedMethods; _status_flags.resize(_threaded_methods.size(), false); } }; template <class T> class CSThread { protected: typedef void (T::*MHT_PTR) (void); vector<MHT_PTR> _threaded_methods; vector<string> _thread_labels; MHT_PTR _stop_f_pt; vector<T*> _elements; vector<T*> _performDelete; vector<CThreadInfo<T>*> _threadlds; vector<pthread_t*> _threads; int _totalRunningThreads; static void * gencker_(void * pArg) { CThreadInfo<T>* vArg = (CThreadInfo<T> *) 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, string 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; } string 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<T>(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 archivo de ejemplo de uso "test.cc" que en Linux he compilado con La clase que encapsula todo el trabajo para procesar un método: g ++ -o mytest.exe test.cc -I. -lpthread -lstdc ++
#include <test.h> #include <vector> #include <iostream> #include <Mutex.h> 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 (attributes), 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<TPuck> 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<vN; ++ii) { // Creating instances of the class that I need to run threads. // If you already have your instances, then just pass them as a // parameter such "mythreadmaker.addElement(&myinstance);" TPuck * vOne = PuckThreadMaker.addElement(); } if (PuckThreadMaker.run() == true) { cout <<"All running!" << endl; } else { cout <<"Error: not all threads running!" << endl; } sleep(1); cout <<"Totale threads creati: " << PuckThreadMaker.runningThreadsCount() << endl; for (unsigned int ii=0; ii<vN; ++ii) { unsigned int kk=0; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; } sleep(2); PuckThreadMaker.stopAll(); cout <<"\n\nAfter the stop!!!!" << endl; sleep(2); for (int ii=0; ii<vN; ++ii) { int kk=0; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; } sleep(5); return 0; } // End of test.cc
fuente
Esta es una pregunta un poco antigua, pero es un problema muy común al que se enfrentan muchos. A continuación se muestra una forma simple y elegante de manejar esto usando std :: thread
#include <iostream> #include <utility> #include <thread> #include <chrono> class foo { public: void bar(int j) { n = j; for (int i = 0; i < 5; ++i) { std::cout << "Child thread executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; int main() { int n = 5; foo f; std::thread class_thread(&foo::bar, &f, n); // t5 runs foo::bar() on object f std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::cout << "Main Thread running as usual"; class_thread.join(); std::cout << "Final value of foo::n is " << f.n << '\n'; }
El código anterior también se encarga de pasar argumentos a la función del hilo.
Consulte el documento std :: thread para obtener más detalles.
fuente
Supongo que esto es porque C ++ está destrozado un poco porque le envía un puntero C ++, no un puntero a función C. Aparentemente hay una diferencia . Intenta hacer un
(void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast)
y luego enviando p.
También hice lo que estás haciendo con una función miembro, pero lo hice en la clase que la estaba usando y con una función estática , que creo que marcó la diferencia.
fuente
C ++: ¿Cómo pasar la función de miembro de clase a 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);
fuente