2009-11-11 4 views
6

Ho una classe lavoratrice come quella qui sotto:Ottenere il valore di ritorno da una funzione boost :: threaded member?

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

E 'destinato ad essere eseguito con boost :: filo e boost :: bind, come:

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

La mia domanda è, come si fa Ottengo il valore di ritorno di Worker :: Do?

Grazie in anticipo.

risposta

7

Non penso che si possa ottenere il valore restituito.

Invece, è possibile memorizzare il valore come membro del lavoratore:

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

e usarlo in questo modo:

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

Grazie, credo di dover ridisegnare un po '. –

2

Inoltre, hai anche alcune chiamate ridondanti per aumentare :: bind() e boost :: function(). È invece possibile effettuare le seguenti:

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

Si può fare questo perché il costruttore di discussione è un wrapper convenienza intorno una chiamata bind interna(). Thread Constructor with arguments

+0

Sembra abbastanza semplice. Grazie, ma la mia implementazione effettiva contiene molte funzioni membro, quindi non posso veramente usare l'operatore(). –

+0

@He Shiming: puoi ancora usarlo senza bind(). Ad esempio, boost :: thread (worker(), & Worker :: Do) (la sintassi potrebbe essere leggermente off poiché è la parte superiore della mia testa). –

-2

Un'altra opzione sta utilizzando la libreria Boost.Lambda. Poi si può scrivere il codice come segue senza cambiare la classe Worker:

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

Ciò è utile soprattutto quando non è possibile modificare la funzione da chiamare. In questo modo, il valore restituito viene avvolto in una variabile locale ret.

+4

Questo eseguirà 'worker.Do()' nel thread corrente, copia il risultato in un oggetto lambda, esegui quel lambda sul nuovo thread (assegnando così il risultato di 'worker.Do()' a 'ret'), e quindi attendere l'esecuzione del nuovo thread da completare. Questo è probabilmente ** non ** il comportamento desiderato, perché esegue 'worker.Do()' nel thread sbagliato. Il modo più semplice e corretto per ottenere risultati da una funzione eseguita in una discussione diversa è l'utilizzo di future e promesse. – Mankarse

13

Un'altra opzione è utilizzare promesse/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. 

E se è possibile utilizzare C++ 0x, quindi utilizzando std :: asincrona impacchetta tutto quanto sopra e basta fare:

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

È possibile dare un'occhiata a il concetto "boost :: future", ref this link