aio_read внутри обработчика сигнала

Я собираюсь использовать aio для асинхронного чтения. Когда aio завершится и сработает обработчик сигнала, мне может понадобиться сделать еще один вызов aio_read и продолжить.

aio_read не упоминается среди безопасных функций (в сигнале man). Однако обычное чтение есть.

Каковы опасности выполнения последующих вызовов aio_read внутри обработчика сигналов aio?


person olegst    schedule 31.03.2016    source источник
comment
Из страницы руководства aio_read: одновременные операции ввода-вывода, определяющие та же структура aiocb дает неопределенные результаты. Если сигнал поступает во время выполнения другого вызова AIO с использованием той же структуры управления, это приведет к проблемам. Думаю, если вы используете отдельную структуру управления и отдельные буферы, это должно быть безопасно. Я не знаю, будут ли проблемы с сигнализацией AIO, если запрос завершится немедленно.   -  person Some programmer dude    schedule 31.03.2016
comment
Не могли бы вы вместо этого использовать отдельный поток, получающий сигналы, используя, например, sigwaitinfo()? Таким образом, вы могли бы выделить новую структуру управления (или использовать мьютексы), чтобы избежать использования уже используемой структуры управления?   -  person Nominal Animal    schedule 31.03.2016


Ответы (1)


Как автор предложенного Boost.AFIO, который может использовать POSIX AIO, я настоятельно рекомендую вообще не использовать POSIX AIO. Вряд ли я одинок в этом мнении, @arvid так же против: http://blog.libtorrent.org/2012/10/asynchronous-disk-io/. Сам API плохо спроектирован и, как следствие, плохо масштабируется под нагрузкой, если только вы не используете специфичные для ОС альтернативы или расширения для AIO, такие как BSD kqueues. POSIX AIO практически бесполезен как есть.

Кроме того, вызовы AIO небезопасны для сигналов в Linux, который вы, вероятно, используете. Это связано с тем, что в Linux они реализованы в пользовательском пространстве с помощью эмуляции на основе пула потоков. В BSD вызовы AIO имеют надлежащий интерфейс системных вызовов ядра, но в ядре превращаются — да, как вы уже догадались — в эмуляцию на основе пула потоков, если не включен O_DIRECT.

Поэтому в POSIX вам гораздо лучше просто всегда использовать пул потоков, если только ваш ввод-вывод не включен с O_DIRECT. Если O_DIRECT действительно всегда включен, Linux предоставляет собственный API ядра, подробно описанный по адресу http://man7.org/linux/man-pages/man2/io_submit.2.html, что довольно эффективно, и в BSD, если вы замените обработку, управляемую сигналами, на BSD kqueues (https://www.freebsd.org/cgi/man.cgi?kqueue, см. EVFILT_AIO), то с O_DIRECT все также может хорошо масштабироваться, в любом случае лучше, чем пул потоков.

Использование обработки завершения на основе сигналов на ЛЮБОЙ платформе POSIX имеет ужасную производительность. AFIO v2 предоставляет универсальный бэкэнд POSIX AIO, и он ужасен, ужасен, ужасен. Избегайте, как чумы.

Обратите внимание, что дизайн синхронного API с пулом потоков является переносимым, хорошо масштабируется для большинства случаев использования, и это то, что я (и действительно arvid) рекомендовал бы всем, у кого нет узкоспециализированных потребностей, таких как написание серверной части базы данных, где вам нужен очень жесткий контроль над физическим уровнем хранения. , и ничего, кроме O_DIRECT|O_SYNC, не вариант.


Хорошо, все сказанное, если вы действительно хотите использовать aio, управляемый сигналом, я предполагаю, что это потому, что вы хотите мультиплексировать свой файловый ввод-вывод с нефайловым вводом-выводом, и поэтому вы не можете использовать aio_suspend() который является правильным API для этого. Способ, которым AFIO v2 обрабатывает это, заключается в использовании сигнала реального времени для прерывания aio_suspend(), когда необходимо обработать что-то, не связанное с aio, затем это можно обработать и перезапустить aio_suspend(). Вы должны быть очень осторожны в обработке гонок и взаимоблокировок, и вам нужно будет тщательно маскировать и демаскировать сигнал для потока, вызывающего aio_suspend(), чтобы сигнал реального времени не терялся и вы не получили потерянное пробуждение. В общем, это не стоит того, поскольку обычно гораздо более низкая производительность ввода-вывода, которую вы получаете через пул потоков + синхронные API.

person Niall Douglas    schedule 31.03.2016