web-dev-qa-db-de.com

Boost-Thread und eine nicht statische Klassenfunktion verwenden

Ich habe also etwas recherchiert und festgestellt, dass Sie ein boost :: thread-Objekt erstellen können, das mit einer nicht-statischen Klassenfunktion gestartet wird, indem Sie "this" und boost :: bind usw. verwenden. Das macht wirklich keinen Sinn Für mich und alle Beispiele, die ich finden konnte, wurde das boost :: thread-Objekt innerhalb derselben Klasse wie die Funktion gestartet, mit der es gestartet wurde, sodass dieses verwendet werden konnte. Ich starte den Thread jedoch in einer anderen Klasse. Ich fürchte also, wenn ich "this" verwende, werde ich sagen, dass "this" von der Klasse stammt, aus der ich den Thread erstellt habe, und nicht aus der, in der sich die Funktion befindet ( Ich bin wahrscheinlich falsch, ich muss mehr über diesen "diesen Typ" lernen. Hier ist ein Beispiel meiner Quelle, mit der ich das Problem habe.

ANNGUI.h

 Klasse ANNGUI 
 {
 private: 
 boost :: thread * GUIThread; 
 Main * GUIMain; 
 Public: 
 // Erstellt die gesamte GUI und alle Unterteile .
 int CreateGUI (); 
} 

ANNGUI.cpp

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

Dies ist nicht die einzige Quelle, aber ich denke, mein Problem liegt irgendwo hier. Ich weiß, dass ich mich irgendwie mit dem "dieses" beschäftigen muss, aber ich bin nicht sicher, wie. Ich könnte eine statische Funktion verwenden, aber ich wollte meine Variablen auch nicht wirklich statisch machen ... Danke.

Gibt es auch eine sehr gute Ressource für die Verwendung von Boost-Bibliotheken? Ihre Website-Dokumentation scheint gut zu sein, aber über meinen Kopf.

43
contrapsych

Das this-Schlüsselwort wird mit boost::bind verwendet, wenn das von Ihnen erstellte Funktionsobjekt an eine object-Member-Funktion gebunden ist. Member-Funktionen können nicht unabhängig von Instanzen existieren. Wenn Sie also ein Funktionsobjekt mit boost::bind aus einer Member-Funktion erstellen, benötigen Sie einen Zeiger auf eine Instanz. Genau das ist das Schlüsselwort this. Wenn Sie das Schlüsselwort this innerhalb einer Memberfunktion einer Klasse verwenden, erhalten Sie einen Zeiger auf die aktuelle Instanz dieser Klasse.

Wenn Sie bind von outside als Klassenelementfunktion aufrufen, können Sie etwa Folgendes sagen:

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

Hier verwenden wir Foo :: some_function als Thread-Funktion. Wir können jedoch nicht this verwenden, da wir bind von main aufrufen. Dasselbe könnte man mit this erreichen, wenn wir bind aus einer Member-Funktion von Foo heraus aufgerufen haben:

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

Wenn eine Member-Funktion statisch ist oder einfach eine reguläre (Nicht-Member-) Funktion ist, benötigen Sie überhaupt keinen Instanzzeiger. Sie würden einfach tun:

boost::thread* thr = new boost::thread(some_regular_function);
81
Charles Salvia

Wie bereits erwähnt, müssen Sie beim Aufruf einer Objektmethode in einem neuen Thread die Adresse dieses Objekts angeben. Sie müssen boost::bind jedoch nicht aufrufen, Sie können den überladenen boost::thread-Konstruktor folgendermaßen verwenden:

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

Wenn sich die Methode in derselben Klasse befindet, verwenden Sie this, um die Adresse der aktuellen Instanz abzurufen, z.

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

Wenn die Methode über Parameter verfügt, können Sie sie nach dem zweiten Argument angeben, z.

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

boost :: bind ist dein Freund (es kann manchmal eine grobe Art sein, ihn zu zeigen)!

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

und machen Sie dann Ihre MainThreadFunc zu einem regulären Mitglied. Das bedeutet, dass Sie die Instanzvariablen direkt wie gewohnt verwenden können.

Etwas wie das:

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
villintehaspam

In solchen Fällen ist es hilfreich, sich nicht statische Elementfunktionen als freie Funktionen vorzustellen, die die Variable this als ersten Parameter verwenden, beispielsweise in Ihrem Fall void MainThreadFunc(Main* this)

boost::thread akzeptiert einen Nullfunktionscode, sodass Sie einen Nullfunktionscode übergeben müssen, der einen Verweis auf die Instanz GUIMain enthält, und GUIMain->MainThreadFunc aufgerufen wird, der, wie ich es oben erklärt habe, etwa MainThreadFunc(GUIMain) wäre. 

Boost (und jetzt auch C++ mit TR1) stellt Helfer zur Verfügung, um solche Funktionen zu erstellen, nämlich boost::bind (oder alternativ boost::lambda::bind). Der Ausdruck boost::bind(f, arg1, arg2, ...) bedeutet "gibt einen Nullfunktionscode zurück, der f(arg1, arg2, ...) aufruft".

Das heißt, Sie können den folgenden Ausdruck verwenden, um den Thread zu erstellen:

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

Wenn Ihr Objekt eine Funktion ist, d. H. Eine operator() hat, können Sie eine Instanz davon an boost::thread übergeben. Die operator() muss nicht statisch sein. Zum Beispiel:

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