4
\$\begingroup\$

I was looking for a thread safe implementation of the observer pattern. I read https://xinhuang.github.io/posts/2015-02-11-how-a-multi-threaded-implementation-of-the-observer-pattern-can-fail.html and was thinking about point 4 "Don't reinvent the wheel, use Boost.Signals2 instead". So I tried the following code and wanted to ask if it is safe to be used in a multithreaded application? What happens if an Observer is destructed during 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();
}
\$\endgroup\$
3
\$\begingroup\$

Boost.Signals2 is a thread-safe library. It uses mutex locking internally. There are some caveats, as explained in this article:

Almost all classes provided by Boost.Signals2 are thread safe and can be used in multithreaded applications. For example, objects of type boost::signals2::signal and boost::signals2::connection can be accessed from different threads.

On the other hand, boost::signals2::shared_connection_block is not thread safe. This limitation is not important because multiple objects of type boost::signals2::shared_connection_block can be created in different threads and can use the same connection object.

but in its simplest and default forms, Boost.Signals2 is multi-threading safe.

Your given example is, indeed, thread-safe.

What happens if an Observer is destructed during notifyObservers?

The slot is disconnected preemptively.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.