对于 boost 信号(现在已弃用),我总是用互斥体包装连接管理和信号调用,以保证线程安全。升压信号 2 应该是开箱即用的。但:
根据Boost Signals2 Thread-Safety文档,当插槽在线程 B 上执行时,可以将插槽与线程 A 断开连接。假设我在线程 A 上创建了一个对象 O 并将 O 的成员函数连接到信号 S在工作线程 B 上执行。现在,由于某些原因,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 的连接?