从 boost::signals2 安全断开
Posted
技术标签:
【中文标题】从 boost::signals2 安全断开【英文标题】:Safely disconnecting from boost::signals2 【发布时间】:2014-06-23 12:38:46 【问题描述】:对于增强信号(现已弃用),我总是使用互斥体包装连接管理和信号调用,以确保线程安全。升压信号 2 应该是开箱即用的。但是:
根据Boost Signals2 Thread-Safety 文档,当插槽在线程 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 的连接?
【问题讨论】:
【参考方案1】:我认为问题实际上出在您的对象上。
Object 不是线程安全的,但是,您似乎同时执行了一个成员函数(信号处理程序)并且它是析构函数。
因此,解决方案是删除此竞争条件。要么
-
锁定类的销毁直到它“空闲”
使用
boost::shared_ptr
/boost::shared_from_this
将信号处理程序绑定到实例。这样,您根本不必显式管理生命周期,并且析构函数将在信号处理程序之后“神奇地”运行(假设它同时断开连接),因为那是对绑定的最后一次引用-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
【讨论】:
但是,您如何解释插槽被调用的事实?他在信号触发之前断开了插槽(这是我通过检查“睡眠”语句看到的)。 @Alex 信号在断开连接之前立即触发。只是处理程序需要一段时间才能完成。 我真的很喜欢 shared_ptr 方法。感谢您的详细回答。 您能详细说明一下吗? “锁定类的破坏,直到它“空闲””我们还必须使用boost::shared_ptr
还是可以使用std::shared_ptr
?以上是关于从 boost::signals2 安全断开的主要内容,如果未能解决你的问题,请参考以下文章