2009-11-11 3 views
6

Ich habe einen Arbeiter Klasse wie unten:Rückgabewert von einer boost :: threaded Memberfunktion?

class Worker{ 
public: 
    int Do(){ 
    int ret = 100; 
    // do stuff 
    return ret; 
    } 
} 

Es ist beabsichtigt ist mit boost :: Gewinde und boost :: bind, wie ausgeführt werden:

Worker worker; 
boost::function<int()> th_func = boost::bind(&Worker::Do, &worker); 
boost::thread th(th_func); 
th.join(); 

Meine Frage ist, wie zu tun Ich bekomme den Rückgabewert von Worker :: Do?

Vielen Dank im Voraus.

Antwort

7

Ich glaube nicht, dass Sie den Rückgabewert erhalten können.

Stattdessen können Sie den Wert als Mitglied der Arbeiter speichern:

class Worker{ 
public: 
    void Do(){ 
    int ret = 100; 
    // do stuff 
    m_ReturnValue = ret; 
    } 
    int m_ReturnValue; 
} 

Und wie so verwenden:

Worker worker; 
boost::function<void()> th_func = boost::bind(&Worker::Do, &worker); 
boost::thread th(th_func); 
th.join(); 
//do something with worker.m_ReturnValue 
+0

Danke ich denke, ich muss ein bisschen neu gestalten. –

2

Darüber hinaus können Sie auch einige redundante Anrufe müssen boost :: bind() und boost :: function(). Sie können die folgenden stattdessen tun:

class Worker{ 
    public: 
     void operator(){ 
      int ret = 100; 
      // do stuff 
      m_ReturnValue = ret; 
     } 
    int m_ReturnValue; 
} 

Worker worker; 
boost::thread th(worker());//or boost::thread th(boost::ref(worker)); 

Sie können dies tun, weil Thema Konstruktor eine Bequemlichkeit Wrapper um eine interne bind() -Aufruf ist. Thread Constructor with arguments

+0

Das sieht ziemlich einfach aus. Danke, aber meine eigentliche Implementierung enthält viele Mitgliedsfunktionen, so dass ich den Operator() nicht wirklich verwenden kann. –

+0

@He Shiming: Sie können es immer noch ohne bind() verwenden. Zum Beispiel, boost :: thread (worker(), & Worker :: Do) (Die Syntax kann etwas abweichen, da es sich um die Spitze meines Kopfes handelt). –

-2

Eine weitere Option ist die Verwendung der Bibliothek Boost.Lambda. Dann können Sie den Code wie folgt schreiben, ohne die Worker Klassenwechsel:

Worker worker; 
int ret; 
boost::thread th(boost::lambda::var(ret) = worker.Do()); 
th.join(); 

Dies ist insbesondere nützlich, wenn Sie nicht die Funktion ändern aufzurufen. Auf diese Weise wird der Rückgabewert in eine lokale Variable ret eingeschlossen.

+4

Dies wird 'worker.Do()' im aktuellen Thread ausführen, das Ergebnis in ein Lambda-Objekt kopieren, das Lambda im neuen Thread ausführen (also das Ergebnis von 'worker.Do()' zu 'ret' zuweisen), Warten Sie dann, bis die Ausführung des neuen Threads abgeschlossen ist. Dies ist höchstwahrscheinlich ** nicht ** das gewünschte Verhalten, weil es 'worker.Do()' im falschen Thread ausführt. Der einfachste und korrekte Weg, Ergebnisse von einer Funktion zu erhalten, die in einem anderen Thread ausgeführt wird, ist die Verwendung von Futures und Versprechen. – Mankarse

13

Eine weitere Option ist die Verwendung von Versprechen/Futures.

class Worker{ 
public: 
    void Do(boost::promise<int> & p){ 
    int ret = 100; 
    // do stuff 
    p.set_value(ret); 
    } 
}; 
//Later... 
boost::promise<int> p; 
boost::thread t(boost::bind(&Worker::Do, &worker, boost::ref(p)); 
int retval = p.get_future().get(); //This will block until the promise is set. 

Und wenn Sie verwenden können, C++ 0x, dann std :: async werden alle oben verpacken und einfach tun:

std::future<int> f = std::async(std::bind(&Worker::Do, &worker)); 
int retval = f.get(); //Will block until do returns an int. 
1
class Worker{ 
public: 
    int Do(){ 
    int ret = 100; 
    // do stuff 
    return ret; 
    } 
} 

Worker worker; 
boost::packaged_task<int> ptask(boost::bind(&Worker::Do, &worker)); 
boost::unique_future<int> future_int = ptask.get_future(); 
boost::thread th(boost::move(ptask)); 
th.join(); 
if (future_int.is_ready()) 
    int return_value = future_int.get(); 

Sie einen Blick darauf werfen können das "boost :: future" konzept, ref this link