添加waitpid后Linux父子进程均挂起的问题排查
问题分析:添加waitpid导致父子进程挂起的原因
核心问题拆解
scanf("%s")的读取特性scanf("%s", cmd)会持续读取字符,直到遇到**空白字符(空格、换行、制表符等)**才会返回并结束本次读取。如果没有读到空白字符,哪怕管道里已经有"close"内容,它也会一直阻塞等待更多输入。管道写端的关闭时机差异
- 未加
waitpid时:父进程写完"close"后直接return 0退出,操作系统会自动关闭父进程持有的所有文件描述符(包括管道的写端)。此时子进程的scanf读取到管道的EOF(写端完全关闭),scanf返回EOF,循环终止,子进程正常退出。 - 添加
waitpid后:父进程写完"close"后调用waitpid等待子进程退出,但此时父进程仍持有管道写端(管道写端未完全关闭,只有父进程关闭后才算彻底关闭)。子进程的scanf既没读到空白字符,也没收到EOF,会一直阻塞在读取操作上;父进程则阻塞在waitpid等待子进程退出,形成双向阻塞死锁。
- 未加
验证与解决方案
方案1:手动关闭管道写端
在父进程写入后立即关闭管道写端,让子进程收到EOF:
B = write(child.fd, "close", 5); if (B != 5) return -1; close(child.fd); // 手动关闭管道写端 waitpid(child.pid, NULL, 0);
此时子进程的scanf会收到EOF,循环终止,子进程正常退出,父进程的waitpid也能顺利返回。
方案2:写入时添加空白终止符
在写入的字符串末尾加上换行符(空白字符的一种),让scanf直接结束读取:
B = write(child.fd, "close\n", 6); // 写入换行符作为终止符 waitpid(child.pid, NULL, 0);
子进程的scanf读到换行符后立即返回,无需等待EOF,父子进程都能正常执行。
总结
问题本质是scanf("%s")的读取逻辑依赖空白符或EOF来结束,添加waitpid后父进程未及时关闭管道写端,也未提供空白终止符,导致双方陷入阻塞死锁。
内容的提问来源于stack exchange,提问作者ABu
相关产品推荐
相关产品推荐

