When to Choose epoll LT vs ET? A Deep Dive into Linux Non‑Blocking I/O

This article explains the differences between epoll's level‑triggered (LT) and edge‑triggered (ET) modes, shows how to use epoll_create, epoll_ctl, and epoll_wait, provides complete C++ examples for read and write handling, and offers practical guidance on avoiding common pitfalls in high‑performance Linux network programming.

Liangxu Linux
Liangxu Linux
Liangxu Linux
When to Choose epoll LT vs ET? A Deep Dive into Linux Non‑Blocking I/O

The author wrote this article to answer a reader’s confusion about Linux epoll’s LT + non‑blocking I/O versus ET + non‑blocking I/O and whether they differ in efficiency.

epoll Overview

Since kernel 2.6, Linux provides the efficient epoll API, which replaces select and poll. To use epoll you first create an epoll file descriptor with epoll_create(int size). The size argument is ignored after Linux 2.6.8 but must be > 0; a successful call returns a non‑negative fd.

#include <sys/epoll.h>
int epoll_create(int size);

Next, you register interest in events on other file descriptors using epoll_ctl:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

The op argument can be EPOLL_CTL_ADD, EPOLL_CTL_MOD or EPOLL_CTL_DEL. The event argument points to an epoll_event structure:

struct epoll_event {
    uint32_t events;   /* same flags as poll */
    epoll_data_t data; /* user‑defined data */
};

typedef union epoll_data {
    void *ptr;
    int   fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;

After registration, epoll_wait blocks (or times out) until one or more events become ready:

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

The events array receives the ready events; the function returns the number of ready fds, 0 on timeout, or -1 on error.

LT vs. ET Trigger Modes

epoll adds a new flag EPOLLET for edge‑triggered (ET) mode; the default is level‑triggered (LT). In LT mode an event remains reported as long as the condition holds (e.g., data is available). In ET mode the event is reported only when the condition changes from false to true.

LT: a ready condition continuously triggers.

ET: only the transition from not‑ready to ready triggers.

For a non‑blocking socket, LT allows you to read whatever data is available without draining the socket completely, while ET requires you to read until recv returns -1 with EAGAIN/EWOULDBLOCK, otherwise you may miss data.

Read‑Event Example (LT)

Compile and run the following program (lines 79 and 134 are left in LT mode). Using nc to send "abcdef" produces seven separate reads because each character keeps the socket readable:

while (true) {
    epoll_event events[1024];
    int n = epoll_wait(epfd, events, 1024, 1000);
    for (size_t i = 0; i < n; ++i) {
        if (events[i].events & EPOLLIN) {
            // read one byte at a time
        }
    }
}
LT read output
LT read output

When the same code is switched to ET mode (by uncommenting the EPOLLET flag) the server prints the data only once, because the read event is not re‑triggered until new data arrives.

ET read output
ET read output

Thus, with ET you must drain the socket completely in the first callback; otherwise the remaining data will be lost.

Write‑Event Example

The article then modifies the program to register both read and write events. In LT mode the write event fires continuously because the socket is always writable, leading to a flood of "EPOLLOUT triggered" messages:

LT write flood
LT write flood

Switching the client fd to ET mode makes the write event fire only once per registration. After handling the partial write you must re‑register the write event if more data remains; otherwise the remaining data will never be sent.

Practical Recommendations

In LT mode, reading does not require draining the socket; you can read as much as you need.

In ET mode, always read until recv returns -1 with EAGAIN/EWOULDBLOCK.

For write handling, LT mode benefits from removing the write event after the buffer is empty to avoid unnecessary CPU usage.

In ET mode, if a write cannot finish, re‑register the write event so the next edge will trigger again.

Understanding these differences is essential for building high‑performance network services on Linux, as epoll is the cornerstone of modern backend I/O multiplexing.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

LinuxepollNon-blocking I/OET modeLT mode
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.