Отмена отложенного вызова обратного вызова, когда владелец задачи уничтожен

0

Я реализую что-то похожее на HTTP-сервер, дизайн: для уже установленного соединения, я хочу повторно использовать его для нескольких запросов, поэтому я запускаю еще одну задачу чтения с async_read на нем, когда запрос завершен, а также запустите deadline_timer, Если в течение 60 секунд нет входа, таймер будет запущен, и соединение будет разрушено. Меня раздражает то, что перед вызовом деструктора соединения будет вызван обратный вызов, который мы установили async_read.

Итак, мой вопрос в том, есть ли способ отменить ожидающую задачу чтения, то есть разрушить соединение без вызова функции обратного вызова?

Если общее описание выше не ясно, то подробный рабочий процесс выглядит следующим образом (код прикреплен внизу):

  1. cleanup() вызывается при завершении запроса;
  2. запустить таймер и другую задачу чтения в cleanup();
  3. если время отсутствует, вызывается HandleTimeout(), и он вызывает stop();
  4. в stop(), выполните чистую работу, а после него экземпляр соединения будет уничтожен.

но после шага 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_;
};
Теги:
boost-asio

1 ответ

1
Лучший ответ

Для этого нет чистого способа. Единственный способ гарантировать, что обработчики, готовые к запуску, такие как Connection::callback(), не будут вызываться:

  • Прекратите обработку io_service событий io_service.
  • Уничтожьте io_service, поскольку деструктор io_service уничтожение всех выдающихся обработчиков.

В примере кода рассмотрите возможность возврата в Connection::callback() если сокет больше не открыт:

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

Также обратите внимание, что аргумента error_code недостаточно, чтобы определить, произошло ли время ожидания. Возможно, что Connection::callback() boost::system::errc::success очередь для вызова с error_code boost::system::errc::success при boost::system::errc::success socket::close(). Следовательно, нет никаких операций для отмены.

  • 0
    Спасибо за ваш ответ, я просто хочу подтвердить, есть ли способ сделать это, теперь ответ, кажется, «Нет», да, мне нужен обходной путь, чтобы сделать это.
  • 0
    @KelvinHu Можете ли вы объяснить, почему вам нужно другое поведение? Если вас раздражает только то, что callback() вызывается перед разрушением Connection , тогда рассмотрите возможность отделения времени жизни Connection от обработчика обратного вызова через boost::weak_ptr . Этот ответ демонстрирует базовую weak_ptr слабого указателя, и этот ответ явно передает weak_ptr обработчику. В любом из решений будет вызываться обработчик, но callback() будет вызываться только в том случае, если Connection активно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню