Linux下使用epoll通过evdev监听多键盘出现卡顿停滞问题问询
问题原因
代码逻辑缺陷
- 你在调用
epoll_wait时传入的超时参数为0,这会让epoll_wait进入非阻塞模式:只要当前没有待处理的输入事件,调用会立刻返回,主循环会持续空转,直接跑满单个CPU核心,高负载下自然会出现卡顿。 - 每次读取输入事件时,你最多只读取4个
input_event结构体。当你高频输入时,内核输入队列中积压的事件数远大于4,未被消费的事件会持续触发EPOLLIN通知,程序会陷入「读一部分事件->返回epoll_wait立刻返回->再读一部分事件」的死循环,直到输入停止、队列排空才会恢复。
系统层面冲突
你在其他系统程序中也能复现卡顿的原因是:你打开evdev设备时没有做独占处理,所有键盘输入事件会同时分发到你的程序、桌面环境的输入管理器、当前聚焦的应用程序等多个消费者。输入频率越高,整个输入链路的分发开销越大,叠加你的程序已经占满CPU,会导致全系统的输入处理都被拖慢。
修复方案
- 把
epoll_wait的超时参数从0改为-1,让它进入阻塞等待模式,没有输入事件时程序会休眠,CPU占用会直接降到接近0。 - 读取
evdev事件时新增循环逻辑,直到read返回EAGAIN错误为止,一次性把当前设备的所有待处理事件全部消费完,避免事件积压反复触发epoll通知。 - 如果你不需要向键盘设备写入数据(如控制背光、宏定义等),把
open的参数从O_RDWR改为O_RDONLY即可,不需要额外的写权限。 - 如果你不需要系统同时处理你监听的键盘输入,可以对设备fd执行
EVIOCGRAB的ioctl调用独占输入,能大幅降低输入分发开销,但执行后系统桌面、其他程序将收不到对应键盘的输入。
内容的提问来源于stack exchange,提问作者Edward Chamberlain
相关产品推荐
相关产品推荐

