Hledal jsem implementaci vzoru pozorovatele bezpečnou pro vlákna. Přečetl jsem https://xinhuang.github.io/posts/2015-02-11-how-a-multi-threaded-implementation-of-the-observer-pattern-can-fail.html a přemýšlel jsem nad bodem 4 „Neobjevujte znovu kolo, místo toho použijte Boost.Signals2“ . Takže jsem zkusil následující kód a chtěl jsem se zeptat, jestli je bezpečné ho použít v aplikaci s více vlákny? Co se stane, když je Observer
zničen během 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(); }
Odpověď
Boost.Signals2 je vlákno -safe knihovna. Používá interně zamykání mutexu. Existují některá upozornění, jak je vysvětleno v tomto článku :
Téměř všechny třídy poskytované Boost.Signals2 jsou bezpečné pro vlákna a lze je použít v aplikacích s více vlákny. Například objekty typu
boost::signals2::signal
aboost::signals2::connection
lze přistupovat z různých vláken.Na druhou stranu
boost::signals2::shared_connection_block
není bezpečné pro vlákna. Toto omezení není důležité, protože více objektů Ó f typeboost::signals2::shared_connection_block
lze vytvořit v různých vláknech a lze použít stejný objekt připojení.
, ale v jeho nejjednodušší a výchozí formuláře, Boost.Signals2 je bezpečný pro více vláken.
Váš uvedený příklad je skutečně bezpečný pro vlákna.
Co se stane, pokud je pozorovatel zničen během notifyObservers?
Slot je preventivně odpojen.