Сброс всех асинхронных обработчиков в boost :: asio - PullRequest
3 голосов
/ 15 апреля 2011

Я запускаю несколько тестов, которые требуют асинхронного взаимодействия, и базовая структура - Asio.Иногда обработчик сохраняется в цикле обработки, даже если тест был прерван по уважительным причинам.Но затем он называется после цели удалены.

Класс Test:

virtual void SetUp()
{
  _client = new Client;
  _server = new Server;

  Service::run();
}

virtual void TearDown()
{
  Service::stop();

  delete _client;
  delete _server;
}

Класс Service:

static void run()
{
  _thread = new asio::thread(boost::bind(&asio::io_service::run, _service));
}

static void stop()
{
  _service->stop();

  _thread->join();
  delete _thread;

  _service->reset();
}

io_service::stop() не блокирует, поэтому в моем случае он становится совершенно бесполезным.Если я удаляю объект io_service в конце функции, обработчик вызываться не будет, но я бы хотел получить лучшее решение для принудительного завершения до удаления объектов.

Примечание: фактический цикл обработки выполняется во втором потоке, но он объединен в оболочку io_service::stop(), и вся проблема, похоже, не связана с потоками.

Я используюAsio (не Boost) 1.4.5, но может рассмотреть вопрос об обновлении (чтобы получить операцию io_service::stopped()?).

EDIT: добавить код оболочки io_service, который, как представляется, уместен согласно комментариям.

Ответы [ 2 ]

5 голосов
/ 15 апреля 2011

Мне кажется, вам нужно немного переосмыслить свой дизайн.io_service::stop действительно асинхронный, как вы заметили.Это заставляет любые вызовы io_service::run() возвращаться как можно скорее.Любые выдающиеся обработчики не вызываются с boost::asio::error::operation_aborted, пока не будет запущен деструктор ~io_service().Чтобы управлять временем жизни объектов, вы должны использовать shared_ptr, поскольку документация предлагает:

Описанная выше последовательность уничтожения позволяет программам упростить управление своими ресурсами с помощью shared_ptr <>.Если время жизни объекта привязано к времени жизни соединения (или некоторой другой последовательности асинхронных операций), shared_ptr объекта будет привязан к обработчикам для всех асинхронных операций, связанных с ним.Это работает следующим образом:

  • Когда заканчивается одно соединение, все связанные асинхронные операции завершаются.Соответствующие объекты-обработчики уничтожаются, а все ссылки на объекты shared_ptr уничтожаются.
  • Чтобы завершить работу всей программы, вызывается функция stop () io_service, которая завершает любые вызовы run () как можно скорее.Деструктор io_service, определенный выше, уничтожает все обработчики, вызывая уничтожение всех ссылок shared_ptr на все объекты подключения.

В частности, у вас есть условие гонки

virtual void TearDown()
{
  service->stop();

  // ok, io_service is no longer running
  // what if outstanding handlers use _client or _server ??

  delete _client;
  delete _server;

  // now you have undefined behavior due to a dangling pointer
}
2 голосов
/ 15 апреля 2011

Рассматривали ли вы использование boost :: shared_ptr для управления временем жизни объекта? В некоторых случаях boost :: enable_shared_from_this может быть полезным. SO обсуждение можно найти здесь .

Другим вариантом может быть присоединение к потоку после вызова stop, чтобы убедиться, что обработчики были вызваны перед удалением объектов.

...