2009-11-11 4 views
6

J'ai une classe ouvrière comme celui ci-dessous:Obtenir la valeur de retour d'une fonction membre boost :: threaded?

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

Il est destiné à être exécuté avec boost :: fil et boost :: bind, comme:

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

Ma question est, comment faire Je reçois la valeur de retour de Worker :: Do?

Merci d'avance.

Répondre

7

Je ne pense pas que vous pouvez obtenir la valeur de retour.

Au lieu de cela, vous pouvez stocker la valeur en tant que membre du travailleur:

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

et de l'utiliser comme ceci:

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

Merci je suppose que je dois refaire un peu de conception. –

2

En outre, vous avez également des appels redondants pour stimuler :: bind() et boost :: function(). Vous pouvez procéder comme suit:

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

Vous pouvez le faire parce que le constructeur de fil est une enveloppe de proximité autour d'un appel bind interne(). Thread Constructor with arguments

+0

Cela semble assez simple. Merci, mais mon implémentation actuelle contient de nombreuses fonctions membres, donc je ne peux pas vraiment utiliser l'opérateur(). –

+0

@He Shiming: Vous pouvez toujours l'utiliser sans bind(). Par exemple, boost :: thread (worker(), & Worker :: Do) (La syntaxe peut être légèrement désactivée puisque c'est le sommet de ma tête). –

-2

Une autre option utilise la bibliothèque Boost.Lambda. Ensuite, vous pouvez écrire le code comme suit sans changer la classe Worker:

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

Ceci est utile en particulier lorsque vous ne pouvez pas changer la fonction à appeler. Comme ceci, la valeur de retour est enveloppée dans une variable locale ret.

+4

Ceci exécutera 'worker.Do()' dans le thread courant, copiera le résultat dans un objet lambda, lancera ce lambda sur le nouveau thread (assignant ainsi le résultat de 'worker.Do()' à 'ret'), puis attendez que l'exécution du nouveau thread se termine. C'est probablement ** pas ** le comportement souhaité, car il exécute 'worker.Do()' dans le mauvais thread. Le moyen le plus simple d'obtenir des résultats à partir d'une fonction exécutée dans un thread différent est d'utiliser des contrats à terme et des promesses. – Mankarse

13

Une autre option consiste à utiliser des promesses/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. 

Et si vous pouvez utiliser C++ 0x, puis en utilisant std :: async conditionnera toute de ce qui précède et le faire:

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

Vous pouvez jeter un oeil à le concept "boost :: future", ref this link

Questions connexes