在销毁任务所有者时取消挂起的任务回调调用

时间:2013-12-21 09:10:43

标签: c++ boost-asio

我正在实现看起来像HTTP服务器的东西,设计是:对于已经建立的连接,我想为多个请求重用它,所以当请求是我的时候,我开始另一个带有async_read的阅读任务完成了,并开始deadline_timer。如果在60秒内没有输入,则会触发定时器并破坏连接。令我烦恼的是,在调用连接的析构函数之前,我们将调用我们设置为async_read的回调。

所以,我的问题是,有没有办法取消挂起的读取任务,即在没有调用回调函数的情况下破坏连接?

如果上面的一般描述不清楚,详细工作流程如下(代码附在底部):

  1. cleanup()在请求完成时被调用;
  2. cleanup();
  3. 中启动计时器和另一个阅读任务
  4. 如果时间已过,则会调用HandleTimeout(),并调用stop();
  5. stop()中,执行清理工作,之后,连接实例将被破坏。
  6. 但是,在第4步之后,将调用callback()函数,该函数在AsyncRead()中注册,那么,有没有办法取消callback()的调用?

    代码:

    class Connection : public boost::enable_shared_from_this<Connection>,
                       private boost::noncopyable {
    public:
        typedef Connection this_type;
    
        void cleanup() {
            timer_.expires_from_now(boost::posix_time::seconds(kDefaultTimeout));
            timer_.async_wait(boost::bind(&this_type::HandleTimeout,
                                          shared_from_this(),
                                          boost::asio::placeholders::error));
            AsyncRead();
        }
    
        void AsyncRead() {
            boost::asio::async_read(*socket_, in_, boost::asio::transfer_at_least(1),
                                    boost::bind(&this_type::callback,
                                                shared_from_this(),
                                                boost::asio::placeholders::error));
        }
    
        void callback(const boost::system::error_code& e) {
            // ...
        }
    
        void HandleTimeout(const boost::system::error_code& e) {
            if(e == boost::asio::error::operation_aborted)
                LDEBUG << "The timeout timer is cancelled.";
            else if(e)
                LERROR << "Error occurred with the timer, message: " << e.message();
            else if(timer_.expires_at()
                       <= boost::asio::deadline_timer::traits_type::now()) {
                LDEBUG << "Connection timed out, close it.";
                stop();
            }
        }
    
        virtual void stop() {
            connected_ = false;
            socket_->close();
    
            connection_manager_.stop(shared_from_this());
        }
    
    private:
        // ...
        boost::asio::deadline_timer timer_;
    };
    

1 个答案:

答案 0 :(得分:1)

没有干净的方法来实现这一目标。保证不会调用即用型处理程序(如Connection::callback())的唯一方法是:

  • 停止处理io_service事件循环。
  • Destroy io_service,因为io_service的析构函数会导致所有未处理的处理程序被销毁。

在示例代码中,如果套接字不再打开,请考虑在Connection::callback()中返回:

void callback(const boost::system::error_code& error)
{
  if (!socket_.is_open()) return;
  // ...
}

另请注意,error_code参数不足以推断是否已发生超时。调用socket::close()时,Connection::callback()可能会在error_code boost::system::errc::success的情况下排队等待调用。因此,没有取消的操作。