epoll_create()返回-1通常因资源或权限问题:先检查/proc/sys/fs/epoll/max_user_watches是否过低(默认65536),再确认RLIMIT_NOFILE限制及cgroup限流。

epoll_create() 返回 -1 怎么排查
直接失败通常意味着系统资源或权限问题,不是代码逻辑错误。先检查 /proc/sys/fs/epoll/max_user_watches 是否被设得太低(默认一般 65536),用 cat /proc/sys/fs/epoll/max_user_watches 查看,临时调高可用 sudo sysctl -w fs.epoll.max_user_watches=2097152;再确认进程没超过 RLIMIT_NOFILE,用 ulimit -n 查,必要时 ulimit -n 1048576(需 shell 启动前设置);最后确认没在容器里被 cgroup 限流——某些 Docker 默认限制 epoll 实例数。
epoll_ctl() 添加监听 socket 时该用 EPOLLIN 还是 EPOLLET
EPOLLIN 是必须的,表示关心读事件;EPOLLET(边缘触发)是可选但强烈推荐的模式。LT(水平触发)下,只要 socket 接收缓冲区有数据,epoll_wait() 就持续返回该 fd,容易导致 busy-loop;ET 模式只在状态变化时通知一次,逼你一次性把数据收完(用 recv(..., MSG_DONTWAIT) 循环直到 EAGAIN 或 EWOULDBLOCK)。不加 EPOLLET 在高并发下 CPU 使用率会明显偏高。
accept() 后的 client fd 忘记设为非阻塞会怎样
会卡死整个事件循环。Linux 下 accept() 返回的 socket 默认是阻塞的,如果后续 recv() 时对方发得慢或断连不及时,recv() 就一直挂起,epoll_wait() 虽然没被阻塞,但你的业务线程卡在系统调用里,无法处理其他就绪 fd。务必在 accept() 后立即执行:int flags = fcntl(client_fd, F_GETFL, 0); fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);。漏掉这步,服务器吞吐量会断崖式下跌,且问题在压力小的时候完全不暴露。
epoll_wait() 返回后怎么安全遍历就绪事件
别直接 for 循环处理 events[] 数组的同时又在回调里 epoll_ctl(EPOLL_CTL_DEL) 或 close() 对应 fd——这会导致数组越界或访问已释放内存。正确做法是:先遍历 events 收集所有要处理的 fd(比如存进一个 vector),再单独处理每个 fd;或者更稳妥地,在处理每个 fd 前先检查 events[i].data.fd 是否仍有效(比如维护一个 std::unordered_map,用 fd 做 key,处理前查表)。另外,epoll_wait() 的 timeout 设为 -1(阻塞等待)比 0(轮询)更省 CPU,除非你在做实时性极高的调度。
EPOLLET 却忘了设 O_NONBLOCK,结果程序看似跑着,实则每次 recv() 都可能卡住——这种 bug 在低负载下根本测不出来。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











