Повышение прерывания :: asio синхронное чтение? - PullRequest
6 голосов
/ 07 декабря 2009

Я использую asio синхронные сокеты для чтения данных по TCP из фонового потока. Это инкапсулировано в "серверный" класс.

Однако я хочу, чтобы поток завершал работу при вызове деструктора этого класса. Проблема заключается в том, что вызов любой из функций чтения блокируется, поэтому поток не может быть легко завершен. В Win32 для этого есть API: WaitForMultipleObjects, который будет делать именно то, что я хочу.

Как бы я достиг аналогичного эффекта с бустом?

Ответы [ 4 ]

2 голосов
/ 21 декабря 2009

Я не нашел простого способа сделать это. Предположительно, есть способы отменить win32 IOCP, но это не очень хорошо работает на Windows XP. MS исправила это для Windows Vista и 7. Рекомендуемый подход для отмены asio async_read или async_write - закрыть сокет.

  • [деструктор] обратите внимание, что мы хотим демонтировать
  • [деструктор] закрыть сокет
  • [деструктор] ожидает обработчиков завершения

  • [завершение], если разрывается, и мы просто не смогли, потому что сокет закрыт, уведомить деструктор, что обработчики завершения выполнены.

  • [завершение] немедленно вернитесь.

Будьте осторожны, если вы решите реализовать это. Закрытие розетки довольно простое. 'ожидание обработчиков завершения', однако, является огромным занижением. При взаимодействии потока сервера и его деструктора может возникнуть несколько тонких угловых случаев и состояний гонки.

Это было достаточно тонко, чтобы мы создали оболочку завершения (аналогично io_service::strand только для синхронной отмены всех ожидающих обратных вызовов завершения.

2 голосов
/ 08 декабря 2009

В нашем приложении мы устанавливаем условие «завершение», а затем используем самостоятельное соединение с портом, который прослушивает поток, поэтому он просыпается, отмечает условие завершения и завершается.

Вы также можете проверить реализацию наддува - если они только выполняют простое чтение в сокете (то есть не используют что-то наподобие WaitForMultipleObjects внутри себя), то вы, вероятно, можете сделать вывод, что нет ничего, что бы просто и чисто разблокировать нить. Если они ожидают нескольких объектов (или порта завершения), вы можете покопаться, чтобы увидеть, не подвержена ли способность пробуждать блокирующий поток снаружи.

Наконец, вы можете убить поток - но вам придется выйти за пределы поддержки, чтобы сделать это, и понять последствия, такие как зависание или утечка ресурсов. Если вы завершаете работу, это может не беспокоить, в зависимости от того, что еще делал этот поток.

1 голос
/ 20 января 2010

Лучший способ - создать socketpair() (что бы это ни было на языке boost::asio), добавить конец считывателя в цикл событий, а затем закрыть конец записывающего устройства. Вы сразу же проснетесь с событием eof в этом сокете.

Затем нить должна добровольно отключиться.

Инициатор потока должен иметь в своем деструкторе следующее:

~object()
{
    shutdown_queue.shutdown();   // ask thread to shut down
    thread.join();               // wait until it does
}
0 голосов
/ 12 июля 2013

Использовать socket.cancel (); завершить все текущие асинхронные операции, которые блокируют сокет. Клиентские сокеты, возможно, должны быть уничтожены в цикле. Мне никогда не приходилось отключать сервер таким образом, но вы можете использовать shared_from_this () и запускать cancel () / close () в цикле аналогично тому, как пример расширенного чата async_writes для всех клиентов.

...