Friday, 15 March 2013

c++ - Safely disconnecting from boost::signals2 -



c++ - Safely disconnecting from boost::signals2 -

with boost signals (which deprecated) wrapped connection management , signal invocation mutex in order thread-safe. boost signals 2 should give out-of-the-box. but:

according boost signals2 thread-safety documentation, possible disconnect slots thread while executing on thread b. let's assume created object o on thread , connected fellow member function of o signal s executed on worker thread b. now, reasons o needs destroyed , disconnected s before. here 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 fellow 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 object o; signals2::connection bc = w.signal.connect(bind(&object::dosomething, &o)); w.start(); this_thread::sleep(posix_time::seconds(2)); bc.disconnect(); } homecoming 0; }

executing code prints:

object::object() virtual object::~object() accessing fellow member in void object::dosomething()

as can see, i'm accessing destroyed object. so, ended wrapping signal 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 missing something? there easier way safely disconnect boost signals 2?

i think problem object.

the object not threadsafe, however, seem simultaneously executing fellow member function (the signal handler) , it's destructor.

the solution, then, remove race condition. either

lock destruction of class until it's "idle" bind signal handler instance using boost::shared_ptr/boost::shared_from_this. way, don't have explicitly manage lifetime @ all, , destructor "magically" run after signal handler (assuming got disconnected in mean time), because that's when lastly reference bind-expression[1] goes out of scope.

here's mean live on coliru, printing:

object::object() accessing fellow member in void object::dosomething() virtual object::~object() full listing #include <iostream> #include <boost/enable_shared_from_this.hpp> #include <boost/make_shared.hpp> #include <boost/thread.hpp> #include <boost/signals2.hpp> #include <boost/bind.hpp> using namespace std; using namespace boost; struct object : boost::enable_shared_from_this<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 fellow 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() { worker w; { // thread auto o = boost::make_shared<object>(); signals2::connection bc = w.signal.connect(bind(&object::dosomething, o)); w.start(); this_thread::sleep(posix_time::seconds(2)); bc.disconnect(); } homecoming 0; }

[1] or c++11 lambda, of course

c++ multithreading boost boost-signals2

No comments:

Post a Comment