The following strategies seem to work well:
- Using a single thread/process with a nonblocking accept() call on the listener socket, regardless of how the program handles the accepted request.
- Using multiple threads/processes with a blocking accept() call in each process. When a connection comes in, this wakes up exactly one accept().
What doesn't work well is EPOLLIN watching the listener socket each thread/process with accept() in a callback. This wakes every thread/process up, though only one can succeed in actually accept()ing. This is just like the bad old days of blocking accept() causing a stampede when a connection would come in.
Is there a way to only have a single thread/process wake up to accept() while still using EPOLLIN? Or should I rewrite to use blocking accept()s, just isolated using threads?
It's not an option to have only a single thread/process run accept() because I'm trying to manage the processes as a pool in a way where each process doesn't need to know whether it's the only daemon accept()ing on the listener socket.