Библиотека POSIX AIO и обработчики обратных вызовов - PullRequest
6 голосов
/ 03 августа 2009

Согласно документации по aio_read / write, библиотека AIO может сообщить вашему приложению 2 способа, что операция ввода-вывода асинхронного файла завершена. Либо 1) вы можете использовать сигнал, 2) вы можете использовать функцию обратного вызова

Я думаю, что функции обратного вызова значительно предпочтительнее сигналов, и, вероятно, их будет намного проще интегрировать в многопоточные библиотеки более высокого уровня. К сожалению, документация для этой функциональности - беспорядок, если не сказать больше. Некоторые источники, такие как справочная страница для структуры sigevent , указывают на то, что необходимо установить для элемента данных sigev_notify в структуре sigevent значение SIGEV_CALLBACK и затем предоставить обработчик функции. Предположительно, обработчик вызывается в том же потоке. Другая документация указывает, что вам нужно установить sigev_notify в SIGEV_THREAD, что вызовет обработчик обратного вызова во вновь созданном потоке.

В любом случае, в моей системе Linux (Ubuntu с ядром 2.6.28) SIGEV_CALLBACK, похоже, нигде не определен, но SIGEV_THREAD работает так, как объявлено. К сожалению, создание нового потока для вызова обработчика обратного вызова кажется действительно неэффективным, особенно если вам нужно вызывать много обработчиков. Было бы лучше использовать существующий пул потоков, аналогично тому, как работает большинство демультиплексоров событий сетевого ввода-вывода. В некоторых версиях UNIX, таких как QNX, есть флаг SIGEV_SIGNAL_THREAD, который позволяет вам вызывать обработчики, используя указанный существующий поток, но, похоже, он недоступен в Linux и даже не является частью POSIX. стандарт.

Итак, возможно ли использовать библиотеку POSIX AIO для вызова пользовательских обработчиков в заранее выделенном фоновом потоке / пуле потоков вместо создания / уничтожения нового потока при каждом вызове обработчика?

Ответы [ 4 ]

2 голосов
/ 06 ноября 2009

Я обычно нахожу, что проще и более портативно моделировать асинхронный ввод-вывод, выполняя обычный ввод-вывод в выделенном фоновом потоке или потоках, отправляя обратные вызовы завершения так, как мне нравится.

1 голос
/ 06 августа 2009

Один из подходов заключается в использовании SIGEV_SIGNAL с сигналом реального времени для «переноса» дескриптора готового файла в обработчик сигнала. Очередь сигналов реального времени и обработчики сигналов выполняются асинхронно в одном потоке, поэтому этот подход более или менее функционально эквивалентен SIGEV_CALLBACK:

/*
 * Warning!  Untested!
 * Also, safe initialization, per-thread signal masking and
 * error-checking omitted.
 */

static void my_callback(int sig, siginfo_t *info, void *context) {
  int fd;

  fd = info->si_value.sival_int;
  /* ...enqueue the fd for processing... */
}

struct sigaction sa;

sa.sa_handler = my_callback;                 /* Register our async callback */
sa.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &sa, NULL);
...

struct aiocb ac;

ac.aio_filedes = some_fd;
ac.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
ac.aio_sigevent.sigev_signo  = SIGRTMIN+1;   /* Associate callback w. aiocb */
....
aio_read(&ac);

Теперь ваш my_callback будет запускаться асинхронно в одном потоке, и вы можете передать fd в ваш поток вспомогательных потоков. См. Также этот бит кода SGI , демонстрирующий, как вернуться к SIGEV_SIGNAL, когда SIGEV_CALLBACK недоступен.

0 голосов
/ 18 февраля 2016

Это действительно старая тема, но она обнаружилась в верхней части Google при рассмотрении этой же проблемы. Теперь есть расширение GNU aio_init, которое позволяет вам указать максимальное количество потоков, которые должен использовать aio, и срок жизни этих потоков.

0 голосов
/ 01 декабря 2010

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

список использования io apis ..

struct aiocb **myaiocb;
 [just an array of aiocb pointers, where each aiocb points to an IO buffer
  and the operation to be performed, etc]
....
lio_listio(LIO_NOWAIT, myaiocb, num_ios, &sigevent);

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

...