Si je mets un set_wait_callback
sur un boost::unique_future
, est-il garanti de ne fonctionner qu'une seule fois?boost :: future - wait_callback est-il garanti pour n'être invoqué qu'une seule fois?
Je suis un peu suspect car quand on regarde le code source que je trouve ce qui suit:
struct relocker
{
boost::unique_lock<boost::mutex>& lock;
relocker(boost::unique_lock<boost::mutex>& lock_):
lock(lock_)
{
lock.unlock();
}
~relocker()
{
lock.lock();
}
private:
relocker& operator=(relocker const&);
};
void do_callback(boost::unique_lock<boost::mutex>& lock)
{
if(callback && !done)
{
boost::function<void()> local_callback=callback;
relocker relock(lock); // unlock mutex?
local_callback();
}
}
void wait(bool rethrow=true)
{
boost::unique_lock<boost::mutex> lock(mutex);
do_callback(lock);
while(!done)
{
waiters.wait(lock);
}
if(rethrow && exception)
{
boost::rethrow_exception(exception);
}
}
Où en do_callback
le mutex est en fait déverrouillé alors que le rappel est invoquée de ma compréhension peut conduire à le rappel étant appelé plusieurs fois si plusieurs threads appellent la fonction wait
?
Le rappel peut-il être appelé plusieurs fois? Est-ce par conception? Ou est-ce que je manque quelque chose?
La raison pour laquelle je suis un peu surpris que dans la norme C++ 11 le async(std::launch::deferred, ...)
(auquel set_wait_callback
est un cousin), semble avoir seule garantie d'invocation:
§30.6.8
L'état partagé n'est pas prêt tant que la fonction n'est pas terminée. Le premier appel à une fonction d'attente non chronométré (30.6.4) sur un objet de retour asynchrone faisant référence à cet état partagé invoquera la fonction différée dans le thread qui a appelé la fonction d'attente.
https://svn.boost.org/trac/boost/ticket/7798 – ronag
Le problème est plus complexe qu'il n'y paraît à première vue. De la documentation, il semble que le rappel doit être appelé chaque fois qu'une fonction d'attente est appelée. "Effets: Stockez une copie de f avec le résultat asynchrone associé à * ceci comme un rappel d'attente.Cela remplacera tout magasin de rappel d'attente existant à côté de ce résultat.Si un thread appelle par la suite l'une des fonctions d'attente sur un avenir ou un coup de pouce :: shared_future associé à ce résultat, et le résultat n'est pas prêt, f (* this) doit être appelé. " –