Je cherchais une implémentation thread-safe du motif dobservateur. Jai lu https://xinhuang.github.io/posts/2015-02-11-how-a-multi-threaded-implementation-of-the-observer-pattern-can-fail.html et je pensais au point 4 « Ne réinventez pas la roue, utilisez plutôt Boost.Signals2 » . Jai donc essayé le code suivant et je voulais demander sil pouvait être utilisé en toute sécurité dans une application multithread? Que se passe-t-il si un Observer
est détruit pendant notifyObservers
?
#include <boost/signals2.hpp> #include <iostream> #include <string> class AbstractObserver { public: using SignalType = boost::signals2::signal<void()>; virtual ~AbstractObserver() = default; virtual void notify() = 0; void registerAtSubject(SignalType &sig) { connection_ = sig.connect([this]() { notify(); }); } private: boost::signals2::scoped_connection connection_; }; class Subject { AbstractObserver::SignalType sig_; public: void registerObserver(AbstractObserver &observer) { observer.registerAtSubject(sig_); } void notifyObservers() const { sig_(); } }; class Observer : public AbstractObserver { std::string id_; public: explicit Observer(std::string id) : id_(std::move(id)) {}; void notify() override { std::cout << "Observer " << id_ << " got notified" << std::endl; } }; int main() { Subject c; { Observer o2("B"); { Observer o1("A"); c.registerObserver(o1); c.notifyObservers(); c.registerObserver(o2); c.notifyObservers(); } c.notifyObservers(); } c.notifyObservers(); }
Réponse
Boost.Signals2 est un fil de discussion -safe. Elle utilise le verrouillage mutex en interne. Il y a quelques mises en garde, comme expliqué dans cet article :
Presque toutes les classes fournies par Boost.Signals2 sont thread-safe et peuvent être utilisées dans des applications multithread. Par exemple, les objets de type
boost::signals2::signal
etboost::signals2::connection
est accessible à partir de différents threads.Dun autre côté,
boost::signals2::shared_connection_block
nest pas thread-safe. Cette limitation nest pas importante car plusieurs objets o f typeboost::signals2::shared_connection_block
peut être créé dans différents threads et peut utiliser le même objet de connexion.
mais dans son formes les plus simples et par défaut, Boost.Signals2 est sûr pour le multi-threading.
Votre exemple donné est, en effet, thread-safe.
Que se passe-t-il si un observateur est détruit pendant notifyObservers?
Le slot est déconnecté de manière préventive.