epoll provides a simple but high-efficient polling mechanism:
(1) epoll_create1 creates a epoll
instance;
(2) epoll_ctl modifies the file descriptors in epoll
instance;
(3) epoll_wait is used to wait I/O events.
Moustique shows a method of using epoll
in multiple-thread program:
auto event_loop_fn = [listen_fd, conn_handler] {
int epoll_fd = epoll_create1(0);
......
epoll_ctl(listen_fd, EPOLLIN | EPOLLET);
const int MAXEVENTS = 64;
......
// Event loop.
epoll_event events[MAXEVENTS];
while (true)
{
int n_events = epoll_wait (epoll_fd, events, MAXEVENTS, -1);
......
}
}
Every thread has its own epoll
instance, and monitors the listen_fd
. When a new connection is established, a dedicated thread will serve it. Since every thread has its own epoll
instance and events
, this will eliminate synchronization among threads.
If you want multiple threads using the same epoll
instance, I think this topic can be a reference.
1 epoll per thread works but I think it takes an important flexibility away. Basically the sockets or fds r partitioned and tied to different threads and can never migrate from one thread to another. If the sockets IO on one thread gets busy, and sockets r very idle on another thread, the other thread cannot be of help since it doesn’t cover the busy sockets.
If u use a thread pool to rescue this issue. A part of ur code could run on one thread now and on a different thread later. At that time, u totally lose the advantage of no need for thread safe synchronization.