4

使用 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高兴。

当然有一个选项:我可以用shared_ptr替换它,并将它传递给每个事件处理程序。这将一直有效,直到程序停止,当 asio io_service停止时,所有对象都将被销毁并且Request将被释放。但是这样我总是必须为Request有一个活动的 asio 事件,否则它将被破坏!我认为这是直接崩溃的方式,所以我也不喜欢这种变体。

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

有没有办法让接受器与连接管理一起使用一些漂亮和安全的方式?我很高兴听到任何建议。

4

3 回答 3

2

使用此库时避免内存泄漏的典型方法是使用 a shared_ptrio_service 文档特别提到了这一点

评论

上述销毁顺序允许程序通过使用shared_ptr<>. 如果对象的生命周期与连接的生命周期(或某些其他异步操作序列)shared_pt相关联,则对象的 r 将绑定到与其关联的所有异步操作的处理程序中。这工作如下:

当单个连接结束时,所有关联的异步操作都完成。相应的处理程序对象被销毁,并且对对象的所有 shared_ptr 引用都被销毁。要关闭整个程序,调用该io_service函数以尽快stop()终止任何调用。run()上面定义的 io_service 析构函数会销毁所有处理程序,导致shared_ptr对所有连接对象的所有引用都被销毁。

对于您的方案,更改您的Listener::handle_accept() 方法以获取boost::shared_ptr<Request>参数。您的第二个顾虑

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

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

class Listener : public boost::enable_shared_from_this<Listener>
{
   ...
};

然后当您调度处理程序时,使用shared_from_this()而不是this绑定到 . 的成员函数时Listener

于 2012-10-02T00:00:00.077 回答
0

如果有人感兴趣,我找到了另一种方法。Listener保存 shared_ptr 到活动连接的列表。io_service::post连接结束/终止是通过Listener::FinishConnection使用asio::strand. 通常我总是用 strand 包装 Request 的方法——它在 DDOS 和/或线程安全方面更安全。FinishConnection因此,从postusing中调用可以strand防止其他线程中的段错误

于 2012-10-08T17:56:52.647 回答
0

不确定这是否与您的问题直接相关,但通过使用Boost Asio库,特别是acceptor您提到的同一个对象,我也遇到了类似的内存泄漏。原来我没有正确关闭服务;一些连接将保持打开状态,并且它们相应的对象不会从内存中释放。调用以下命令消除了Valgrind报告的泄漏:

acceptor.close();

希望这对某人有用!

于 2016-06-10T17:16:27.483 回答