ZMQ poll()突然频繁返回"Interrupted system call"问题求助
poll()频繁返回EINTR的思路 核心本质
EINTR的含义是系统调用被信号中断,ZMQ设计本身允许该情况并建议重试,但频繁出现必然存在异常触发源。
可能的触发因素及排查步骤
虚拟机资源调度干扰
VMware虚拟机在宿主机(Windows 10)资源紧张时(比如CPU/内存过载、宿主机后台跑高负载任务、Windows自动更新),会向Guest系统发送信号(如SIGINT、SIGALRM)来调度资源。可以通过以下命令监控进程收到的信号:strace -e signal -p <你的进程PID>或用
perf追踪信号事件:perf record -e signal:* -p <PID> perf report重点关注频繁触发的信号类型及发送方。
系统更新后的底层变化
你更新到了5.15.0-67内核,内核对信号的处理逻辑、或ZMQ依赖的系统库(如libc、libzmq)可能在更新后有细微调整。可以尝试回退到之前的稳定内核版本,验证问题是否消失。另外检查libzmq版本是否近期有更新:dpkg -l | grep libzmq代码/第三方库的信号引入
虽然你认为替换MySQL类无关,但新的MySQL客户端库可能定时发送信号(如心跳检测的SIGALRM),或代码清理时误引入了信号处理逻辑变化。检查代码中是否有signal()、sigaction()相关调用,同时排查第三方库是否注册了信号处理函数。此外,系统定时任务、监控工具(如cron、sysstat)也可能向进程发送信号。宿主机环境波动
宿主机Windows 10的后台任务(自动更新、杀毒扫描、磁盘整理)会抢占资源,导致虚拟机CPU频繁暂停/恢复,内核可能因此向进程发送中断信号。可以关闭宿主机非必要后台程序,或调整VMware资源分配(增加CPU核心、内存),观察问题是否缓解。
临时缓解方案
在明确信号来源前,可在poll()调用前后临时屏蔽特定信号(需避免屏蔽必要信号),减少中断次数。例如针对SIGALRM:
sigset_t mask, old_mask; sigemptyset(&mask); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &old_mask); int rc = zmq_poll(items, nitems, timeout); sigprocmask(SIG_SETMASK, &old_mask, NULL); if (rc == -1 && errno == EINTR) { // 重试逻辑 }
内容的提问来源于stack exchange,提问作者Synopsis

