2011-01-03 15 views
38

Así que investigué y encontré que puedes crear un objeto boost :: thread y hacer que comience con una función de clase no estática usando "this" y aumentar :: bind, etc. Realmente no tiene mucho sentido para mí y todos los ejemplos que pude encontrar tenían el objeto boost :: thread lanzado dentro de la misma clase que la función con la que estaba empezando, por lo que podría usarse. Sin embargo, estoy lanzando el hilo en una clase diferente, así que me temo que al usar "esto", diré que "esto" es de la clase de la que estoy creando el hilo, en lugar de aquella en la que está la función (Probablemente estoy equivocado, necesito aprender más sobre este "este" chico). Aquí hay un ejemplo de mi fuente con la que estoy teniendo el problema.Usando el hilo de refuerzo y una función de clase no estática

ANNGUI.h

 
class ANNGUI 
{ 
private: 
    boost::thread *GUIThread; 
    Main *GUIMain; 
public: 
    // Creates the entire GUI and all sub-parts. 
    int CreateGUI(); 
} 

ANNGUI.cpp

 
int ANNGUI::CreateGUI() 
{ 
     GUIMain = new Main(); 
    GUIThread = new boost::thread(GUIMain->MainThreadFunc); 
}; 

Esto no es todo la fuente, pero creo que mi problema es aquí en alguna parte, yo sé que tengo que hacer frente a la "esto" de alguna manera, pero no estoy seguro de cómo. Podría usar una función estática, pero tampoco quería que mis variables estuvieran estáticas. Gracias.

Además, ¿hay algún recurso muy bueno para usar cualquier biblioteca de impulso? La documentación de su sitio web parece buena, pero por encima de mi cabeza.

Respuesta

73

La palabra clave this se utiliza con boost::bind cuando el objeto de la función que está creando está ligada a una función miembro objeto. Las funciones miembro no pueden existir aparte de las instancias, por lo que al crear un objeto functor a partir de una función miembro con boost::bind, necesita un puntero a una instancia. Eso es exactamente lo que es realmente la palabra clave this. Si usa la palabra clave this dentro de una función miembro de una clase, lo que obtiene es un puntero a la instancia actual de esa clase.

Si se va a llamar bind desde fuera una función miembro de la clase, se podría decir algo como:

int main() 
{ 
    Foo f; 
    boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, &f)); 
} 

Aquí, estamos usando Foo :: some_function como nuestra función hilo. Pero no podemos usar this porque estamos llamando al bind desde main. Pero lo mismo podría lograrse utilizando this si llamamos bind desde dentro de una función miembro de Foo, así:

void Foo::func1() 
{ 
    boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, this)); 
} 

Si una función miembro es estático, o es simplemente una función regular (no miembro), entonces no necesitas un puntero de instancia en absoluto. Usted acaba de hacer:

boost::thread* thr = new boost::thread(some_regular_function); 
+2

¿Se requiere 'nuevo'? Si creo el hilo como variable local normal, ¿no funcionará? –

+0

que pasa si llamo boost :: thread * thr = new boost :: thread (boost :: bind (y Foo :: some_function, this)); ¿¿dos veces?? –

3

boost :: bind es tu amigo (¡a veces puede tener una forma aproximada de mostrarlo)!

uso GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain));

y luego hacer su MainThreadFunc un miembro regular. Eso significa que puede usar las variables de instancia directamente como lo haría normalmente.

Algo como esto:

class GUIMain { 
public: 
    GUIMain() : m_Member(42) {} 

    void MainThreadFunc() { 
    // use all members as you would normally do 
    std::cout << m_Member << std::endl; 
    } 

private: 
    int m_Member; 
}; 
3

En casos como este, es útil pensar en las funciones miembro no estático funciona como libres que toman el this como primer parámetro, por ejemplo, en su caso void MainThreadFunc(Main* this).

boost::thread acepta un funtor nularia, por lo que tiene que pasar un funtor nularia que contiene una referencia a la instancia GUIMain y llama GUIMain->MainThreadFunc el cual, visto como he explicado anteriormente, sería algo así como MainThreadFunc(GUIMain).

Boost (y ahora también C++ con TR1) proporciona ayudantes para crear dichos functors, es decir, boost::bind (o alternativamente boost::lambda::bind). La expresión boost::bind(f, arg1, arg2, ...) significa "return a nullary functor que llama al f(arg1, arg2, ...)".

Dicho esto, se puede utilizar la siguiente expresión para crear el hilo:

GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain)) 
+0

+1 La única respuesta que explica * por qué * tenemos que usar boost :: bind! –

+0

Simplemente no obtengo lo que parece el functor devuelto por 'boost :: bind'. De acuerdo con su definición, debe llamar a 'Main :: MainThreadFunc (GUIMain)', pero 'MainThreadFunc' no toma ningún argumento. ¿Cómo se ve el funtor internamente? –

39

Como otros han mencionado, cuando se quiere llamar a un método de objeto en un nuevo hilo, que tiene que suministrar la dirección de ese objeto. Pero no es necesario llamar a boost::bind, puede utilizar la sobrecarga boost::thread constructor de la siguiente manera:

GUIThread = new boost::thread(&Main::MainThreadFunc, GUIMain); 

Si el método está en la misma clase que utiliza this para obtener la dirección de la instancia actual, por ejemplo:

t = new boost::thread(&myclass::compute, this); 

Si el método tiene parámetros, puede especificar ellos después del segundo argumento, por ejemplo:

t = new boost::thread(&myclass::compute, this, p1, p2); 
+0

Muy completo. Gracias. – Michael

+0

¿por qué no simplemente 'GUIThread = boost :: thread (& Main :: MainThreadFunc, GUIMain);'? .. – Pavel

+0

@Pavel, porque el OP usa 'new' en su pregunta. La pregunta se centra en llamar a un método en un nuevo hilo; mirar las diferentes formas de cómo construir un objeto de hilo no es realmente relevante para esta pregunta. – maxschlepzig

1

Si el objeto es un fu nctor, es decir, tiene un operator(), puede pasar una instancia del mismo al boost::thread. El operator() no necesita ser estático. Por ejemplo:

#include <boost/thread.hpp> 

struct th { 
    void operator()(); 
}; 

void th::operator()() 
{ 
    for (;;) { 
     // stuff 
    } 
} 

int main() 
{ 
    th t; 
    boost::thread my_thread(t); // takes a copy of t ! 
    my_thread.join(); // blocks 
    return 0; 
} 
Cuestiones relacionadas