我将使用boost::asio来处理异步连接请求。这个方法很有效,但是有一个问题需要解决。使用典型的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));
}
代码能够正常运行,但存在一个问题:Request对象是用普通的new创建的,因此可能会出现内存“泄漏”。其实不是真正的泄漏,只有在程序停止时才会泄漏,但我希望让valgrind满意。
当然也有一种选择:我可以用shared_ptr替换它,并将其传递给每个事件处理程序。这种方法在程序停止时仍然有效,因为asio io_service停止时,所有对象都将被销毁并释放Request。但是,这样做我总是必须拥有一个活动的asio事件来处理Request,否则它将被销毁!我认为这是直接导致崩溃的方法,所以我也不喜欢这个变体。
第三种选择是:使用Listener
保存活动连接的共享指针列表。看起来很好,我更愿意使用这个方案,除非找到更好的方法。缺点是:由于该方案允许在空闲连接上进行“垃圾收集”,因此不安全:从Listener中删除连接指针将立即销毁它,这可能导致其他线程中某些连接处理程序仍活动时发生段错误。使用互斥锁无法解决这个问题,因为在这种情况下我们几乎必须锁定任何东西。
有没有一种可以使acceptor与连接管理以更美观和安全的方式工作的方法?我很高兴听到任何建议。
shared_ptr
/enable_shared_from_this
方法行不通?我不理解一个活动的asio事件的上下文。此外,如果Request
没有创建自己的异步调用链,并将其寿命绑定到该链,则其他对象是否会维护对Request
对象的句柄? - Tanner Sansbury