Linux POSIX环境下消费者线程串口写导致程序运行一段时间后挂起咨询
问题根因
你遇到的挂起问题确实和串口侧的堵塞直接相关,核心原因有2个:
- 你开启了串口硬件流控
CRTSCTS,如果串口对端没有及时读取数据,会通过流控信号阻止本地发送,此时串口的write调用会进入永久阻塞状态,且不会返回错误码。 - 你的代码逻辑错误导致串口发送冗余数据,加速了发送缓冲区耗尽:
mq_receive返回的ret是实际收到的消息字节数,但你每次调用write时都写整个rcvBuffer的大小(82字节),额外多发送10字节的无效数据,快速占满串口默认的4KB左右发送缓冲区。
你观察到的「修改MAX_MSG_SIZE后挂起前接收的消息数量变化」「刚好51次挂起」完全符合这个逻辑:按默认参数每次发送82字节计算,51次累计发送约4182字节,刚好打满4KB的串口发送缓冲区,后续write直接阻塞。
修复方案
- 优先关闭硬件流控测试验证:将
UartInit中tty->c_cflag |= CRTSCTS;改为tty->c_cflag &= ~CRTSCTS;,确认是否还会出现挂起问题,若必须使用流控则需要排查对端的流控信号逻辑。 - 修复串口写逻辑:不要发送整个缓冲区,只发送实际收到的消息长度,将
write(fd, rcvBuffer, sizeof(rcvBuffer))改为write(fd, rcvBuffer, ret)。 - 修复宏定义优先级bug:将
MSG_BUFFER_SIZE的定义改为#define MSG_BUFFER_SIZE (MAX_MSG_SIZE + 10),避免后续其他地方调用时出现运算符优先级错误。 - 可选优化:如果允许数据丢失,可在打开串口时添加
O_NONBLOCK标志将串口设为非阻塞模式,write返回EAGAIN错误时跳过本次发送或者做重试逻辑,避免线程永久挂起。 - 可选优化:补充串口配置中缺失的
VMIN参数,在tty.c_cc[VTIME] = 0;后添加tty.c_cc[VMIN] = 1;,避免后续串口读操作出现异常。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

