访问串口时收发线程疑似阻塞的代码逻辑排查咨询
UART多线程读写程序逻辑问题排查
问题场景
我用C语言写了一套UART读写程序,测试时出现异常:
- 初始阶段通过第三方UART工具发送
test1,触发recv线程读取到result1,程序正常执行到printf("2->3"); - 再次用工具发送
result2,recv线程完全没进入case 3:分支,而且第三方UART工具在主线程退出前无法再发送任何测试字符串。
测试示例代码
typedef struct devpara { int fd; int num; // 这里缺分号,编译报错 } devpara_t; int g_step = 1; // 初始步骤 // 缺少全局锁和条件变量的定义与初始化 pthread_mutex_t g_mutex; pthread_cond_t g_cond; int main() { int ret = 0; devpara_t *dpara = malloc(sizeof(devpara_t)); pthread_t rtid, wtid; // 缺失的线程ID变量,之前未定义 // 结构体成员名写错:结构体里是fd,这里用了hd dpara->hd = openuart("/ttyS0"); // 参数为O_RDWR | O_NOCTTY if (dpara->hd < 0) return -1; configuart(dpara->hd, 115200, 8, 1, NOPAR, 1 /* 停止位 */); // 第一个线程的ID存在wtid里,后面被第二个线程覆盖 ret = pthread_create(&wtid, NULL, recvthread, (void *)dpara); if (ret < 0) { perror("pthread_create failed\n"); return -1; } // 线程函数名写错:要创建的是sendthreadfunc,这里写了sendthread ret = pthread_create(&wtid, NULL, sendthread, (void *)dpara); if (ret < 0) { perror("pthread_create failed\n"); return -1; } // rtid未定义,编译报错,主线程无法正确等待recv线程退出 pthread_join(rtid, NULL); pthread_join(wtid, NULL); if(dpara->hd >= 0) closeuart(dpara->hd); if(NULL != dpara) free(dpara); return ret; } void *recvthread(void *para) { unsigned char buf[128] = {0}; int ret = -1; devpara_t *localpara = (devpara_t *)para; for (;;) { ret = read(localpara->fd, buf, 128); // 没判断read是否成功,要是read返回-1(读失败)还继续处理buf if (ret <= 0) continue; pthread_mutex_lock(&g_mutex); // 变量名写错:buf写成buff,导致字符串永远匹配失败 switch(g_step) { case 1: if (!strncmp(buff, "result1", strlen("result1"))) pthread_cond_signal(&g_cond); break; case 2: if (!strncmp(buff, "result2", strlen("result2"))) pthread_cond_signal(&g_cond); break; case 3: if (!strncmp(buff, "result3", strlen("result3"))) pthread_cond_signal(&g_cond); break; default: break; } pthread_mutex_unlock(&g_mutex); } } void *sendthreadfunc(void *para) { FILE *fp; devpara_t *localpara = (devpara_t *)para; for (;;) { pthread_mutex_lock(&g_mutex); pthread_cond_wait(&g_cond, &g_mutex); switch(g_step) { case 1: printf("1->2"); senddata(localpara->fd, "test2"); g_step = 2; break; case 2: printf("2->3"); // fopen参数写错:第二个参数应该是字符串"r",不是裸r fp = fopen("test.config", r); if (NULL == fp) return NULL; // 直接退出send线程,后续case3没人处理 // 没关闭文件,资源泄漏 fclose(fp); g_step = 3; break; case 3: // 缺case3的处理逻辑,收到result3后没响应 printf("3->end"); break; } pthread_mutex_unlock(&g_mutex); }
UART配置代码
termios_cfg.c_cflag |= CLOCAL; termios_cfg.c_cflag |= CREAD; termios_cfg.c_oflag &= ~OPOST; termios_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); termios_cfg.c_cc[VTIME] = 1; termios_cfg.c_cc[VMIN] = 1; // 刷新缓冲区 tcflush(fd, TCIFLUSH); ret = tcsetattr(fd, TCSANOW, &termios_cfg); if (0 != ret) { printf("tcsetattr failed!\n"); ret = -1; }
问题根源分析
- 变量/函数名拼写错误:
recvthread里把接收缓冲区buf写成buff,strncmp永远匹配失败,这是result2无法触发case3的核心原因。- 结构体成员
fd被写成hd,导致UART文件描述符未正确赋值,读写操作实际无效。 - 线程创建时指定的函数名
sendthread与实际定义的sendthreadfunc不匹配,send线程根本没创建成功。
- 线程管理错误:
- 两个线程共用同一个
wtid变量,第一个线程的ID被覆盖,pthread_join(rtid)里rtid未定义,主线程无法正确等待线程退出,可能提前终止导致UART资源未释放。
- 两个线程共用同一个
- 同步机制未初始化:
- 全局锁
g_mutex和条件变量g_cond没初始化,调用同步接口会触发未定义行为,线程间的信号传递完全失效。
- 全局锁
- 资源与逻辑漏洞:
sendthreadfunc中打开文件后未关闭,造成资源泄漏;打开失败直接返回导致send线程提前退出,g_step=3后没有线程处理后续逻辑。recvthread未判断read返回值,读取失败时仍处理无效缓冲区,可能引发程序异常。
- UART字节流处理问题:
- 当前UART配置是
VMIN=1+VTIME=1,读到1个字符或等待100ms就返回,第三方工具发送的字符串可能被拆分成多次读取,strncmp因不完整字符串匹配失败。建议添加帧头帧尾或长度字段来确保读取到完整指令。
- 当前UART配置是
内容的提问来源于stack exchange,提问作者Rui
相关产品推荐
相关产品推荐

