安全地从boost::信号断开
Safely disconnecting from boost::signals2
对于boost信号(现在已弃用),我总是用互斥锁包装连接管理和信号调用,以便线程安全。2号信号应该能让它开箱即用。但是:
根据Boost Signals2线程安全文档,当线程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(); }
我错过了什么吗?是否有一种更简单的方法来安全地断开boost信号2?
我认为问题出在你的物品上。
Object不是线程安全的,然而,你似乎同时执行一个成员函数(信号处理程序)和它的析构函数。
那么,解决方案就是删除这个竞争条件。
- 锁定类的销毁,直到它"空闲"
- 使用
boost::shared_ptr
/boost::shared_from_this
绑定信号处理程序到实例。这样,您根本不必显式地管理生命周期,析构函数将"神奇地"在信号处理程序之后运行(假设它同时断开),因为这是对绑定表达式[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λ,当然
相关文章:
- Qt VTK交互风格的信号到小部件
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 当套接字连接断开时检测C/C++Unix
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- 如何在没有信号的情况下从C++执行QML插槽
- 线程之间的布尔停止信号
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 当用户在qtablewidget中输入单元格时,如何获得信号?C++
- 有可能在信号处理程序中设置promise吗
- 代码在我的计算机上运行良好,但是在将其提交给coursera时遇到未知的信号11问题
- 升压信号2将插槽传递到成员功能以断开连接
- 断开信号失败
- 增强信号:在类接口中公开信号本身或连接/断开方法
- 升压信号2 - 通过插槽断开连接时出错
- 如何在Qt中运行函数时断开所有信号
- 我仍然需要从Qt5.5中的信号断开lambda吗?
- 正确的方式断开信号从两个qobject不被销毁/删除
- 安全地从boost::信号断开
- 断开并稍后重新连接Qt信号
- Boost信号自动断开lambda槽