tags:

views:

252

answers:

4

One can use poll/select when writing a server that can service multiple clients all in the same thread. select and poll, however need a file descriptor to work. For this reason, I am uncertain how to perform simple asynchronous operations, like implementing a simple callback to break up a long running operation or a delayed callback without exiting the select/poll loop. How does one go about doing this? Ideally, I would like to do this without resorting to spawning new threads.

In a nutshell, I am looking for a mechanism with which I can perform ALL asynchronous operations. The windows WaitForMultipleObjects or Symbian TRequestStatus seems a much more suited to generalized asynchronous operations.

A: 

select() and poll() are syscalls - it means that your program is calling OS kernel to do something and your program can do nothing while waiting for return from kernel, unless you use other thread.

Although select() and poll() are used for async I/O, these functions (syscalls) are not async - they will block (unless you specify some timeout) until there is something happened with the descriptor you are watching.

Best strategy would be to check descriptors time to time (specifying small timeout value), and if there is nothing, do what you want to do in idle time, otherwise process I/O.

qrdl
Polling regularly is very inelegant. Windows has WaitForMultipleObjects with is much more general
doron
@deus-ex-machina399 That's what select() and poll() does in POSIX. And that's what you have asked for.
qrdl
A: 

You could take advantage of the timeout of select() or poll() to do your background stuff periodically:

for ( ;; ) {
   ...
   int fds = select(<fds and timeout>);
   if (fds < 0) {
       <error occured>
   } else if if (fds == 0) {
       <handle timeout, do some background work.>
   } else {
       <handle the active file descriptors>
   }
 }
Richard Pennington
A: 

For an immediate callback using the select loop, one can use one of the special files like /dev/zero that are always active. The will allow select the exit soon but will allow other files to become active as well.

For timed delays, I can only thing of using the timeout on select.

Both of the above don't feel great, so please send better answers.

doron
A: 

For arbitrary callbacks, maintain a POSIX pipe (see pipe(2)). When you want to do a deferred call, write a struct consisting of a function pointer and optional context pointer to the write end. The read end is just another input for select. If it selects readable, read the same struct, and call the function with the context as argument.

For timed callbacks, maintain a list in order of due time. Entries in the list are structs of e.g. { due time (as interval since previous callback); function pointer; optional context pointer }. If this list is empty, block forever in select(). Otherwise, timeout when the first event is due. Before each call to select, recalculate the first event's due time.

Hide the details behind a reasonable interface.

fizzer