2008-09-17 12 views

Respuesta

15

Normalmente utilizo una función miembro estática de la clase, y uso un puntero a la clase como el parámetro void *. Esa función puede realizar el procesamiento de subprocesos o llamar a otra función miembro no estática con la referencia de clase. Esa función puede hacer referencia a todos los miembros de la clase sin una sintaxis incómoda.

+0

La función de envoltura debe tener un enlace C. Los punteros a funciones de funciones libres pueden ser incompatibles debido al enlace de lenguaje – sellibitze

11

Tienes que arrancar usando el vacío parámetro *:

class A 
{ 
    static void* StaticThreadProc(void *arg) 
    { 
    return reinterpret_cast<A*>(arg)->ThreadProc(); 
    } 

    void* ThreadProc(void) 
    { 
    // do stuff 
    } 
}; 

... 

pthread_t theThread; 
pthread_create(&theThread, NULL, &A::StaticThreadProc, this);
+0

Gracias por esto mientras investigo mi pthread actual en C++. Sin embargo, esto no entra en conflicto con la respuesta que se encuentra aquí: http://stackoverflow.com/questions/592160/static-vs-extern-c. ¿No necesita agregar extern "C" de alguna manera? Además, ¿hay algún problema con hacer el trabajo real en el StaticThreadProc? –

23

Esto puede hacerse simplemente mediante el uso de la biblioteca de impulso, así:

#include <boost/thread.hpp> 

// define class to model or control a particular kind of widget 
class cWidget 
{ 
public: 
void Run(); 
} 

// construct an instance of the widget modeller or controller 
cWidget theWidget; 

// start new thread by invoking method run on theWidget instance 

boost::thread* pThread = new boost::thread(
    &cWidget::Run,  // pointer to member function to execute in thread 
    &theWidget);  // pointer to instance of class 

Notas:

  • Esto usa una función de miembro de clase ordinaria. No es necesario agregar miembros adicionales, estáticos que confunden su interfaz de clase
  • Simplemente incluya boost/thread.hpp en el archivo de origen donde inicia el hilo. Si recién está empezando con el impulso, se puede ignorar todo el resto de ese paquete grande e intimidante.

En C++ 11 se puede hacer lo mismo pero sin impulso

// define class to model or control a particular kind of widget 
class cWidget 
{ 
public: 
void Run(); 
} 

// construct an instance of the widget modeller or controller 
cWidget theWidget; 

// start new thread by invoking method run on theWidget instance 

std::thread * pThread = new std::thread(
    &cWidget::Run,  // pointer to member function to execute in thread 
    &theWidget);  // pointer to instance of class 
+0

Entonces, no me opongo a esto ... pero nadie en la tienda en la que trabajo usa boost ...sería un gran cambio de paradigma. Es una biblioteca bastante grande también ... ¿cuál es la mejor manera de empezar a usarlo? – jdt141

+0

Bueno, en realidad no es una biblioteca, solo un montón de incluye. Así que puedes elegir una pequeña parte que te atraiga y comenzar por incluir esos encabezados donde los necesites. Solo un par de nuevas características del lenguaje que puede usar aquí y allá según lo considere apropiado. – ravenspoint

+2

+1 para impulsar! No es una decisión falsa, pero ¿su variable 'cMyClass theClass' no debería llamarse' cMyClass theObject' ya que no es una clase sino solo una instancia? Creo que esto sería más claro. –

3

he utilizado tres de los métodos descritos anteriormente. Cuando usé por primera vez el enhebrado en C++ utilicé funciones de miembro estáticas, luego funciones de amigo y finalmente las bibliotecas BOOST. Actualmente prefiero BOOST. En los últimos años me he convertido en el intolerante BOOST.

BOOST es a C++ como CPAN a Perl. :)

0

La biblioteca de impulso proporciona un mecanismo de copia, que ayuda a transferir la información del objeto al nuevo hilo. En el otro ejemplo de boost, boost :: bind se copiará con un puntero, que también se copiará. Por lo tanto, tendrá que cuidar la validez de su objeto para evitar un puntero colgante. Si implementa el operador() y proporciona un constructor de copia en su lugar y pasa el objeto directamente, no tiene que preocuparse por ello.

Una solución mucho mejor, lo que evita un montón de problemas:

#include <boost/thread.hpp> 

class MyClass { 
public: 
     MyClass(int i); 
     MyClass(const MyClass& myClass); // Copy-Constructor 
     void operator()() const;   // entry point for the new thread 

     virtual void doSomething();  // Now you can use virtual functions 

private: 
     int i;       // and also fields very easily 
}; 

MyClass clazz(1); 
// Passing the object directly will create a copy internally 
// Now you don't have to worry about the validity of the clazz object above 
// after starting the other thread 
// The operator() will be executed for the new thread. 
boost::thread thread(clazz);    // create the object on the stack 

El otro ejemplo impulso crea el objeto hilo en el montón, aunque no hay un sentido hacerlo.

+0

¿Qué sucede si hay dos o más métodos diferentes en la clase que necesita ejecutar? Usar el operador() es inteligente (¿lindo?) Pero, ¿es la mejor manera, dado que solo puedes tener uno por clase? – ravenspoint

+1

Otro pensamiento: insistir en copiar la clase cada vez que se inicia el método puede no ser la mejor manera si la copia de clase es costosa (por ejemplo, requiere mucha memoria) o incluso puede romper el diseño si la clase es un singleton. En cualquier caso, lo que está sucediendo tendrá que documentarse con cuidado, ya que está sucediendo mucho más que simplemente ejecutar un método. – ravenspoint

+0

Es una buena idea envolver un mecanismo que le permite llamar a varias funciones de una clase, pero rara vez lo necesitará. Primero pensé que era una buena manera, pero luego noté los efectos secundarios. Si implementa algo con un mecanismo de copia, me gustaría. Pasar el objeto en lugar del puntero al boost :: bind copiará el objeto varias veces. Pero de lo contrario, usted tendrá problemas en la mayoría de los casos, excepto en Singletons y en administración de objetos "locos". – CSpille

Cuestiones relacionadas