2011-01-03 8 views
38

Zrobiłem kilka badań i odkryłem, że możesz utworzyć obiekt boost :: thread i rozpocząć od niestatycznej funkcji klasowej za pomocą "tego" i zwiększenia :: bind itd. To naprawdę nie ma dla mnie większego sensu i wszystkie przykłady, jakie mogłem znaleźć, zawierały obiekt boost :: thread uruchamiany w tej samej klasie co funkcja, z której zaczynał się więc to może być użyte. Ja jednak uruchamiam wątek w innej klasie, więc obawiam się, że używając "tego", powiem, że "to" pochodzi z klasy, z której utworzę wątek, a nie z tej funkcji (Prawdopodobnie jestem w błędzie, muszę dowiedzieć się więcej o tym "tym" facecie). Oto przykład mojego źródła, z którym mam problem.Używanie wątku doładowania i niestanowiącej klasy funkcji

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); 
}; 

To nie jest tym źródłem, ale myślę, że mój problem jest gdzieś tutaj, wiem, że mam do czynienia z "to" jakoś, ale nie jestem pewien jak. Mogłem użyć funkcji statycznej, ale tak naprawdę nie chciałem również uczynić moich zmiennych statycznymi. Dzięki.

Czy istnieje również bardzo dobry zasób do korzystania z bibliotek doładowania? Ich dokumentacja witryny wygląda dobrze, ale nad moją głową.

Odpowiedz

73

this kluczowe jest używana z boost::bind gdy obiekt funkcji tworzysz jest związany z obiektu funkcji członka. Funkcje członkowskie nie mogą istnieć poza instancjami, więc podczas tworzenia obiektu funktora poza funkcją składową z boost::bind potrzebny jest wskaźnik do instancji. Dokładnie to jest słowo kluczowe this. Jeśli użyjesz słowa kluczowego this w funkcji składowej klasy, otrzymasz wskaźnik do bieżącej instancji tej klasy.

Jeśli było zadzwonić bind z poza funkcji składowej klasy, można powiedzieć coś takiego:

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

Tutaj używamy Foo :: some_function jak nasz funkcji wątku. Ale nie możemy użyć this, ponieważ dzwonimy pod numer bind z main. Ale to samo można osiągnąć stosując this jeśli nazwaliśmy bind od wewnątrz funkcji składowej Foo, tak:

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

Jeśli funkcja członek jest statyczna, czy jest to po prostu regularne function (non-member) wtedy w ogóle nie potrzebujesz wskaźnika instancji. byłoby po prostu zrobić:

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

Czy 'nowy' jest absolutnie wymagany? Jeśli utworzę wątek jako normalną zmienną lokalną, czy to nie zadziała? –

+0

co jeśli zadzwonię do boost :: thread * thr = new boost :: thread (boost :: bind (& Foo :: some_function, this)); dwa razy?? –

3

boost :: bind to Twój przyjaciel (czasami może to jednak być trudne)!

użycie GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain));

a następnie dokonać MainThreadFunc stałym członkiem. Oznacza to, że możesz używać zmiennych instancji bezpośrednio, tak jak normalnie.

coś takiego:

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

W takich przypadkach warto pomyśleć o non-statycznych funkcji składowych jako darmowe funkcje, które podejmują this jako pierwszy parametr, na przykład w przypadku void MainThreadFunc(Main* this).

boost::thread akceptuje sygnalnych funktor, więc trzeba przekazać mu sygnalnych funktor, który zawiera odwołanie do instancji GUIMain i wywołuje GUIMain->MainThreadFunc który widział jak wyjaśniono powyżej, byłoby coś podobnego MainThreadFunc(GUIMain).

Zwiększenie (a teraz także C++ z TR1) zapewnia pomocników w tworzeniu takich funktorów, mianowicie boost::bind (lub alternatywnie boost::lambda::bind). Wyrażenie boost::bind(f, arg1, arg2, ...) oznacza "zwraca funktor nullary, który wywołuje f(arg1, arg2, ...)".

Mimo to, można użyć następującego wyrażenia, aby utworzyć wątek:

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

+1 Jedyna odpowiedź, która wyjaśnia * dlaczego * musimy użyć boost :: bind! –

+0

Po prostu nie otrzymuję tego, co zwrócił funktor po 'boost :: bind'. Zgodnie z twoją definicją powinien on wywoływać 'Main :: MainThreadFunc (GUIMain)', ale 'MainThreadFunc' nie przyjmuje żadnych argumentów. Jak funktor wygląda wewnętrznie? –

39

Jak inni wspomniano, gdy chcesz wywołać metodę obiektu w nowym wątku, musisz podać adres tego obiektu. Ale nie trzeba zadzwonić boost::bind, można użyć przeciążony boost::thread konstruktora takiego:

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

Jeśli metoda jest w tej samej klasie użyć this aby uzyskać adres bieżącej instancji, np:

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

Jeśli metoda ma parametry, można określić je po drugim argumencie, np:

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

Bardzo wszechstronny. Dzięki. – Michael

+0

dlaczego nie po prostu 'GUIThread = boost :: thread (& Main :: MainThreadFunc, GUIMain);'? .. – Pavel

+0

@Pavel, ponieważ OP używał słowa 'new' w swoim pytaniu. Pytanie skupia się na wywołaniu metody w nowym wątku; spojrzenie na różne sposoby tworzenia obiektu wątku nie jest tak istotne dla tego pytania. – maxschlepzig

1

Jeśli obiekt jest fu nctor, tj. ma numer operator(), możesz przekazać jego instancję do boost::thread. Model operator() nie musi być statyczny. Na przykład:

#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; 
}