C++ asio接受器避免内存泄漏

C++ asio接受器避免内存泄漏,c++,networking,boost,boost-asio,C++,Networking,Boost,Boost Asio,使用boost::asio我使用async_accept来接受连接。这很好,但有一个问题,我需要一个如何处理它的建议。使用典型的async_accept: Listener::Listener(int port) : acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), port)) , socket(io) { start_accept(); } void Listener::start_a

使用boost::asio我使用async_accept来接受连接。这很好,但有一个问题,我需要一个如何处理它的建议。使用典型的async_accept:

  Listener::Listener(int port)
        : acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), port))
        , socket(io) {
          start_accept();
  }

  void Listener::start_accept() {
      Request *r = new Request(io);
      acceptor.async_accept(r->socket(), 
        boost::bind(&Listener::handle_accept, this, r, placeholders::error));
  }
工作正常,但存在一个问题:请求对象是使用普通的新建创建的,因此它可能会导致内存“泄漏”。不是真正的泄漏,它只在程序停止时泄漏,但我想让valgrind高兴

当然有一个选项:我可以将其替换为共享\u ptr,并将其传递给每个事件处理程序。这将一直工作到程序停止,当asioio\U服务停止时,所有对象将被销毁,请求将被释放。但这样一来,对于请求,我必须始终有一个活动的asio事件,否则它将被销毁!我认为这是直接导致崩溃的方法,所以我也不喜欢这种变体

UPD第三个变量:
侦听器
保存到活动连接的共享ptr列表。看起来很棒,我更喜欢用这个,除非能找到更好的方法。缺点是:由于此模式允许在空闲连接上执行“垃圾收集”,因此不安全:从侦听器中删除连接指针将立即破坏它,当连接的某些处理程序在其他线程中处于活动状态时,会导致segfault。使用互斥不能解决这个问题,在这种情况下,我们必须锁定几乎任何东西


有没有一种方法可以让接受者以一种漂亮而安全的方式与连接管理一起工作?我将很高兴听到任何建议。

使用此库时避免内存泄漏的典型方法是使用
共享\u ptr
io\u服务
特别提到这一点

评论

上述销毁顺序允许程序简化 通过使用
共享\u ptr
管理他们的资源。物体的位置 生存期与连接(或其他连接)的生存期相关联 异步操作序列),对象的
共享\u pt
r将 被绑定到所有相关异步操作的处理程序中 用它。这项工作如下:

当单个连接结束时,所有关联的异步操作 完成相应的处理程序对象被销毁,所有 对象的共享\u ptr引用将被销毁。关闭 在整个程序中,调用
io\u服务
函数
stop()
终止 任何
run()。已定义io_服务析构函数
上述操作将销毁所有处理程序,导致所有
共享的\u ptr
引用都指向所有 要销毁的连接对象

对于您的场景,请更改
Listener::handle\u accept(
)方法以获取
boost::shared\u ptr
参数。你的第二个顾虑

从侦听器中删除连接指针将立即销毁它, 当某些连接的处理程序处于活动状态时,什么会导致segfault 在另一个线程中。使用互斥不能解决这个问题在这种情况下,我们必须 几乎可以锁定任何东西

通过从类中的该
模板继承
boost::enable_shared_来缓解:

class Listener : public boost::enable_shared_from_this<Listener>
{
   ...
};
类侦听器:public boost::从此\u启用\u共享\u
{
...
};

然后,当您分派处理程序时,在绑定到
侦听器的成员函数时,使用
shared\u from\u this()
而不是
this
,如果有人感兴趣,我找到了另一种方法<代码>侦听器
保存到活动连接的共享ptr列表。连接结束/终止是通过
io\u service::post
进行的,它调用
Listener::FinishConnection
并用
asio::strand
包装。通常,我总是用strand包装请求的方法,这在DDOS和/或线程安全方面更安全。因此,从
post
使用
strand
调用
FinishConnection
可以防止其他线程中的segfault

不确定这是否与您的问题直接相关,但我使用Boost Asio库也有类似的内存泄漏,特别是您提到的同一个
接受程序
对象。结果发现我没有正确地关闭服务;某些连接将保持打开状态,其相应的对象将不会从内存中释放。打电话给以下人员消除了Valgrind报告的泄漏:


希望这对别人有用

这不是
监听器
类的设计问题吗,或者是使用
绑定
的策略,而不是使用函数对象,这不是一个函数对象=)的问题,但无论如何,我不明白普通函数是如何解决这个问题的。@p请你详细说明一下为什么惯用的
shared\u ptr
/
enable\u shared\u from\u这种
方法不起作用?我不了解asio活动的背景。另外,如果
Request
没有创建自己的异步调用链,并将其生命周期绑定到该链上,那么其他对象是否正在维护
Request
对象的句柄?@twsansbury作为“活动asio事件”,我指的是一些挂起的异步读取/异步写入或任何保持连接对象活动的东西。关于
请求
对象存储-它是一个很好的变体,但也有缺点;我将它添加到问题中,正如我所提到的,在这种情况下,如果没有活动的异步事件,连接就不可能存在,那么对我来说有什么不好呢?因为我必须处理其他异步连接(获取数据)来处理每个请求,所以获取数据时使用连接的时间是空闲的,而不是事件it@PSIAlt我已经更新了我的答案,您想使用此()中的
shared\u()
。谢谢您的帮助,我会试试这个,看起来很合理
acceptor.close();