POSIX AIO Library and Callback Handlers

According to the aio_read / write documentation, there are basically 2 ways that the AIO library can tell your application that the asynchronous file I / O operation has completed. Or 1) you can use the signal, 2) you can use the callback function

I think callback functions are much preferable to signals, and it would probably be much easier to integrate into higher-level multithreaded libraries. Unfortunately, the documentation for this functionality is at least a mess. Some sources, such as the man page for sigevent struct , indicate that you need to set the sigev_notify data member in sigevent struct to SIGEV_CALLBACK, and then provide a function handler. Presumably, the handler is called on the same thread. Other documentation indicates that you need to set sigev_notify to SIGEV_THREAD, which will output the callback handler to the newly created stream.

In any case, on my Linux system (Ubuntu with 2.6.28 kernel), SIGEV_CALLBACK does not seem to be defined anywhere, but SIGEV_THREAD works as advertised. Unfortunately, creating a new thread to call the callback handler seems really inefficient, especially if you need to call many handlers. It would be better to use an existing thread pool, similar to how demultiplexers work for work in an input-output network. Some versions of UNIX, such as QNX, have the SIGEV_SIGNAL_THREAD flag, which allows you to call handlers using the specified existing thread, but this does not seem to be available on Linux, and it does not seem to be part of the POSIX standard.

So, is it possible to use the POSIX AIO library in such a way as to call user handlers in a previously allocated background thread / threadpool, and not create / destroy a new thread each time the handler is called?

+6
linux posix aio
source share
4 answers

I usually find it simpler and more portable to simulate asynchronous I / O by doing normal I / O on a dedicated background thread or threads, sending completion callbacks the way I like.

+2
source share

One approach is to use SIGEV_SIGNAL with a real-time signal to β€œtransfer” the finished file descriptor to a signal handler. The signal queue modes and signal handlers are executed asynchronously in one thread, therefore this approach is more or less functionally equivalent to 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); 

Now your my_callback will run asynchronously on the same thread, and you need to pass fd to your auxiliary thread. See Also this SGI Code Bit for a demonstration of how to return to SIGEV_SIGNAL when SIGEV_CALLBACK unavailable.

+1
source share

If you are worried that multiple threads are created / destroyed for each completion call, why don't you do batch operations?

use io apis list ..

 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); 

The advantage with an IO list is that the callback handler is called only after all the IOs in the list have completed (successfully / unsuccessfully). You can check the status of each I / O with aio_return.

0
source share

This is a really old thread, but it appeared at the top of Google when considering this issue. There is currently a GNU extension aio_init that allows you to specify the maximum number of threads that aio_init should use and the lifetime of these threads.

0
source share

All Articles