Является рекурсивным вызовом boost :: asio :: io_context :: run_one () valid? [Дубликат]

Для подсказок посмотрите на имя имени класса, которое выдает ошибку и номер строки, например: Ошибка компиляции [ERROR] \ applications \ xxxxx.java: [44,30] ошибка: не удается найти символ

Еще одна причина - неподдерживаемый метод для java-версии: jdk7 vs 8. Проверьте свой% JAVA_HOME%

4
задан Tanner Sansbury 23 February 2015 в 16:04
поделиться

2 ответа

Действительно.

Для семейства функций, которые обрабатывают io_service, run() является единственным с ограничениями:

Функция run() не должна вызываться из потока, который в настоящее время вызывает один из run(), run_one(), poll() или poll_one() на том же объекте io_service.

Однако я склонен думать, что в документации также должно быть указано то же замечание для run_one(), поскольку вложенный вызов может привести к его блокировке неограниченно для любого из следующих случаев [1]:

  • единственная работа в io_service - это выполняемый в настоящий момент обработчик
  • для реализаций портов завершения ввода-вывода, единственная работа была отправлена ​​из текущего обработчика и io_service имеет подсказку о параллельности 1

Для портов завершения ввода-вывода Windows демультиплексирование выполняется во всех потоках, обслуживающих io_service с помощью GetQueuedCompletionStatus() . На высоком уровне потоки, вызывающие GetQueuedCompletionStatus(), функционируют так, как если бы они были частью пула потоков, позволяя ОС отправлять работу в каждый поток. Поскольку ни один поток не отвечает за операции демультиплексирования с другими потоками, вложенные вызовы poll() или poll_one() не влияют на диспетчеризацию операций для других потоков. В документации указано:

Демультиплексирование с использованием портов завершения ввода-вывода выполняется в всех потоках, которые вызывают io_service::run(), io_service::run_one(), io_service::poll() или io_service::poll_one().


Для всех других систем механизмов демультиплексирования одноразовый сервис io_service используется для операций демультиплексирования операций ввода-вывода. Точный механизм демультиплексирования можно найти в Замечаниях по реализации платформы :

Демультиплексирование с использованием [/dev/poll, epoll, kqueue, select ] выполняется в одном потоков, который вызывает io_service::run(), io_service::run_one(), io_service::poll() или io_service::poll_one().

Реализация механизма демультиплексирования немного отличается, но на высоком уровне:

  • у io_service есть главная очередь, из которой потоки потребляют готовые к выполнению операции для выполнения
  • каждого вызова процесс io_service создает приватную очередь в стеке, которая используется для управления операциями в режиме блокировки
  • , в конечном итоге происходит синхронизация с основной очередью, где происходит блокировка и операции частной очереди

Когда io_service сконструирован , построенный , он может быть предоставлен в основной очереди, информируя другие потоки и позволяя им потреблять из основной очереди. подсказка параллелизма , предполагающая, сколько потоков реализовано ион должен позволять работать одновременно. Когда реализации портов завершения ввода-вывода снабжены подсказкой параллелизма 1, они оптимизированы для максимально возможного использования частной очереди и отсрочки синхронизации с основной очередью. Например, когда обработчик отправляется через post():

  • , если он вызван извне обработчика, тогда io_service гарантирует безопасность потока, поэтому он блокирует основную очередь перед тем, как обходить обработчик.
  • , если он вызывается из обработчика, отправленный обработчик помещается в очередь в приватную очередь, откладывает отсрочку синхронизации с основной очередью до тех пор, пока не будет необходимо.

Когда вложенный poll() или poll_one(), становится необходимым, чтобы частная очередь была скопирована в основную очередь, так как операции, которые будут выполняться, будут потребляться из основной очереди. Этот случай явно проверен в реализации :

// We want to support nested calls to poll() and poll_one(), so any handlers
// that are already on a thread-private queue need to be put on to the main
// queue now.
if (one_thread_)
  if (thread_info* outer_thread_info = ctx.next_by_key())
    op_queue_.push(outer_thread_info->private_op_queue);

Если не указана никакая подсказка параллелизма или любое значение, отличное от 1, то отправленные обработчики синхронизируются в основной очереди каждый раз. Поскольку частную очередь не нужно копировать, вложенные вызовы poll() и poll_one() будут работать как обычно.


1. В проекте networking-ts отмечается, что run_one() нельзя вызывать из потока, который в настоящее время вызывает run().

5
ответ дан Tanner Sansbury 21 August 2018 в 19:31
поделиться

Является ли вызов asio :: io_service :: poll () или poll_one () вложенным или рекурсивным способом (т. е. изнутри обработчика) действительным?

Ситаксически, это действительно. Но, его не очень хорошая проблема в каждом обработчике, вы должны запустить poll (). Кроме того, ваша трассировка стека будет расти до очень больших размеров, и вы можете столкнуться с большими проблемами со стеком.

1
ответ дан PSIAlt 21 August 2018 в 19:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: