Asio在包含处理程序的类被破坏后调用处理程序
Asio calls handler after the class containing the handler gets destructed
我有一个类X,它在构造函数中引用了boost::asio::io_service
和一个连接的boost::astio::ip::tcp::socket
。该类处理网络数据的发送和接收。
我遇到的一个问题是,主代码要求X发送一条消息X::sendMessage()
,然后主代码在下一行删除X。因此,X调用boost::asio::async_write
,使用lambda作为处理程序,然后X被删除,它的析构函数被调用,从而关闭套接字。再也没有X了。但过了一段时间,boost::asio::io_service
调用了boost::asio::async_write
调用中使用的lambda处理程序,该调用现在位于一个已销毁的类中,boost::system::error_code
设置为"Success"。
有没有什么方法可以告诉lambda类已经被破坏,它不应该干扰类的成员和方法?
也许我可以以某种方式取消在~X()
中调用lambda处理程序?尽管写操作可能已经完成并计划由boost::asio::io_service
执行处理程序,但实际上没有什么可取消的。
注意,我不能对boost::asio::io_service
对象做任何事情,因为它是由主代码传递给X的,它处理的不仅仅是网络。
class X
{
public:
X(boost::asio::io_service &io, boost::asio::ip::tcp::socket socket)
: io(io), socket(std::move(socket)){ }
~X()
{
if (socket.is_open()) {
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket.close();
}
}
void X::sendMessage()
{
boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
[this](boost::system::error_code ec, std::size_t /*length*/)
{
std::cout << ec.message() << std::endl; // Success!
// `this' is invalid though
if (!ec) {
// code
} else {
// code
}
});
}
private:
boost::asio::io_service &io;
boost::asio::ip::tcp::socket socket;
编辑:
现在,我只创建了一个带有bool的共享指针,我将其传递给lambdas,并在析构函数中设置为true,这样lambdas就可以判断对象是否已经被析构函数。这是一个肮脏的黑客,但目前有效。不过,从长远来看,我希望有一个更优雅的解决方案。
如果要确保对象在asio
框架具有对它的引用时保持活动状态,请将指向该对象的共享所有权智能指针传递到lambda表达式中。例如:
class X : public enable_shared_from_this<X>
// ...
boost::shared_ptr<X> that = this->shared_from_this();
boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
[that](boost::system::error_code ec, std::size_t /*length*/)
解决方案是将X类成员声明为共享指针(即boost::shared_ptr<X> m_x;
),并将类实例传递给lambda。请参阅下面修改后的代码。
它防止类实例破坏,直到Asio调用lambda。
#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
class X : private boost::noncopyable, public boost::enable_shared_from_this<X>
{
private:
struct Data {
char *data;
size_t size;
};
Data m;
public:
X(boost::asio::io_service &io, boost::asio::ip::tcp::socket socket)
: io(io), socket(std::move(socket)){ }
~X()
{
if (socket.is_open()) {
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket.close();
}
}
void X::sendMessage()
{
auto self = shared_from_this();
boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
[self](boost::system::error_code ec, std::size_t /*length*/)
{
std::cout << ec.message() << std::endl; // Success!
// `this' is invalid though
if (!ec) {
// code
}
else {
// code
}
});
}
private:
boost::asio::io_service &io;
boost::asio::ip::tcp::socket socket;
};
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 在遍历处理程序的向量时注册和注销处理程序
- 有可能在信号处理程序中设置promise吗
- 在信号处理程序中捕获C++未处理的异常并恢复应用程序
- 在C++程序中使用的迭代器中未处理的异常
- 有关图像处理应用程序的硬件和软件安全性的建议
- 通过安装信号处理程序关闭多线程应用程序
- QDateTime::toString() 在退出处理程序中使用时失败
- 如何在 WindowProc 处理程序中区分箭头键和数字键盘?
- async_write完成处理程序最早何时完成?
- C++事件系统 - 多态事件和事件处理程序
- 使用信号处理程序处理从 FIFO 接收的数据
- 使用独立的 c++ 程序处理用 C 编写的字符设备驱动程序
- C 程序处理两个文件,而不是一个文件
- 是什么让这个程序处理缓慢?(C++)
- QT 中的应用程序>处理消息?
- MongoDB C++驱动程序处理副本集连接故障
- 使用 OpenCV 程序处理多页 PDF