views:

53

answers:

2

A couple of days ago I had to investigate a problem where my application was showing abnormally high CPU usage when it was (apparently) in idle state. I tracked the problem down to a loop which was meant to block on a recvfrom call while the socket had been set to O_NONBLOCK-ing resulting in a spin lock. There were two ways of solving the problem: set the socket to blocking or poll for available data on the socket using poll or select. I chose the former as it was simpler. But I am wondering why any one would create a non-blocking socket and then poll on it separately. Doesn't a blocking socket do the same? What are the uses cases where one would use a non-blocking socket and poll combination? Are there any advantages to it in general cases?

A: 

resulting in a spin lock.

That condition normally is called a tight loop.

There were two ways of solving the problem: set the socket to blocking or poll for available data on the socket using poll or select. I chose the former as it was simpler.

Are you sure that other code parts do not already use poll() (or select()) and expect the socket to be in non-blocking mode?

Otherwise, then yes, the switch to the blocking mode is the simplest solution.

Best backward-compatible solution would have been before calling recvfrom() to use poll() to wait for the socket to become readable. That way ensures that other parts of the code would work precisely as before.

But I am wondering why any one would create a non-blocking socket and then poll on it separately. Doesn't a blocking socket do the same?

For the case of recvfrom() no major difference is known to me.

What are the uses cases where one would use a non-blocking socket and poll combination? Are there any advantages to it in general cases?

Could be a simple coding mistake. Or somebody might have thought that recv'ing in tight loop would somehow increase the performance.

Dummy00001
`SIGPIPE` is just as applicable to non-blocking sockets as it is to blocking ones.
caf
@caf: True. Fixed.
Dummy00001
+2  A: 

Using poll() or select() with a non-blocking file descriptor gives you two advantages:

  • You can set a timeout to block for;
  • You can wait for any of a set of file descriptors to become useable.

If you only have a single file descriptor (socket) to wait for, and you don't mind waiting indefinitely on it, then yes; you can just use a blocking call.

The second advantage is really the killer use case for select() and friends. It means that you can handle multiple socket connections, as well as standard input and standard output and possibly file I/O, all with a single thread of control.

caf