Szukałem bezpiecznej wątkowo implementacji wzorca obserwatora. Czytałem https://xinhuang.github.io/posts/2015-02-11-how-a-multi-threaded-implementation-of-the-observer-pattern-can-fail.html i zastanawiałem się nad punktem 4 „Nie”, aby wymyślać koło na nowo, zamiast tego użyj Boost.Signals2 . Wypróbowałem więc poniższy kod i chciałem zapytać, czy można go bezpiecznie używać w aplikacji wielowątkowej? Co się stanie, jeśli Observer
zostanie zniszczony podczas 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(); }
Odpowiedź
Boost.Signals2 to wątek -bezpieczna biblioteka. Wewnętrznie korzysta z blokowania mutexów. Istnieją pewne zastrzeżenia, zgodnie z opisem w tym artykule :
Prawie wszystkie klasy dostarczane przez Boost.Signals2 są bezpieczne dla wątków i mogą być używane w aplikacjach wielowątkowych. Na przykład obiekty typu
boost::signals2::signal
iboost::signals2::connection
można uzyskać z różnych wątków.Z drugiej strony
boost::signals2::shared_connection_block
nie jest bezpieczny dla wątków. To ograniczenie nie jest ważne, ponieważ wiele obiektów o typ fboost::signals2::shared_connection_block
można tworzyć w różnych wątkach i używać tego samego obiektu połączenia.
ale w jego Najprostsze i domyślne formularze, Boost.Signals2 jest bezpieczna dla wielowątkowości.
Podany przykład jest rzeczywiście bezpieczny dla wątków.
Co się stanie, jeśli Observer zostanie zniszczony podczas notifyObservers?
Slot zostanie odłączony zapobiegawczo.