使用boost信号(现已弃用)我总是使用互斥锁包装连接管理和信号调用,以保证线程安全。提升信号2应该提供开箱即用的功能。但是:
根据Boost Signals2 Thread-Safety文档,当线程A在线程B上执行时,可以断开线程A的插槽。 假设我在线程A上创建了一个对象O,并将O的成员函数连接到在工作线程B上执行的信号S.现在,由于某些原因,O需要被销毁,因此之前与S断开连接。这是一个例子:
#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;
}
执行此代码打印:
Object::Object()
virtual Object::~Object()
Accessing member in void Object::doSomething()
正如我们所看到的,我正在访问一个已经被破坏的对象。所以,最后我再次使用互斥锁包装信号。
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(); }
我错过了什么吗?是否有更简单的方法可以安全地断开升压信号2?
答案 0 :(得分:4)
我认为问题实际上是你的对象。
对象不是线程安全的,但是,你似乎在同时执行一个成员函数(信号处理程序)和它的析构函数。
然后,解决方案是消除这种竞争条件。
boost::shared_ptr
/ boost::shared_from_this
将信号处理程序绑定到实例。这样,您根本不必明确管理生命周期,而且析构函数只会“神奇地”#34;在信号处理程序之后运行(假设它在同一时间内断开连接),因为当最后一个对bind-expression [1] 的引用超出范围时。这就是我的意思 Live On Coliru ,打印:
Object::Object()
Accessing member in void Object::doSomething()
virtual Object::~Object()
#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 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 A
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();
}
return 0;
}
[1] 或C ++ 11 lambda,当然