With boost signals (which is now deprecated) I always wrapped connection management and signal invocation with a mutex in order to be thread-safe. Boost signals 2 should give that out-of-the-box. But:
According to the Boost Signals2 Thread-Safety documentation, it is possible to disconnect slots from thread A while they are executing on thread B. Let's assume I created an object O on thread A and connected a member function of O to a signal S that is executed on worker thread B. Now, for some reasons O needs to be destroyed and thus disconnected from S before. Here is an example:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;
struct Object
{
Object() : x(0) {cout << __PRETTY_FUNCTION__ << endl;}
virtual ~Object() {cout << __PRETTY_FUNCTION__ << endl;}
void doSomething()
{
this_thread::sleep(posix_time::milliseconds(4200));
cout << "Accessing member in " << __PRETTY_FUNCTION__ << endl;
x++;
}
int x;
};
class Worker
{
public:
Worker() {}
virtual ~Worker() {myThread.join();}
void Start() { myThread = thread(bind(&Worker::DoThread, this)); }
signals2::signal<void ()> Signal;
private:
void DoThread()
{ // thread B
Signal();
}
thread myThread;
};
int main(int argc, char* argv[])
{
Worker w;
{ // thread A
Object o;
signals2::connection bc = w.Signal.connect(bind(&Object::doSomething, &o));
w.Start();
this_thread::sleep(posix_time::seconds(2));
bc.disconnect();
}
return 0;
}
Executing this code prints:
Object::Object()
virtual Object::~Object()
Accessing member in void Object::doSomething()
As we can see, I'm accessing an already destroyed object. So, finally I ended up wrapping the signal with a mutex again.
connection Worker::Connect(..) { mutex::scoped_lock l(_mutex); Signal.connect(..); }
void Worker::Disconnect(connection c) { mutex::scoped_lock l(_mutex); c.disconnect(); }
void Worker::Raise() { mutex::scoped_lock l(_mutex); Signal(); }
Am I missing something? Is there an easier way to safely disconnect from boost signals 2?