单进程将stdout重定向到pipe后读取时read调用挂起问题咨询
问题原因分析
标准IO库的缓冲机制是触发挂起的核心原因:
- C标准库的
printf属于标准IO函数,默认对终端类设备采用行缓冲策略,只有遇到换行符、缓冲区满、主动调用fflush、程序正常退出这几种场景,才会把用户态缓冲区的数据刷入内核对应的文件描述符。你代码里的printf(in)输出的是不带换行符的qwerty,数据始终停留在用户态的stdout缓冲区,根本没写入pipe,内核的pipe通道里没有可用数据,read调用自然会一直阻塞等待。 - 你后续测试用的
write版本代码能正常运行,是因为write是系统调用,直接把数据提交给内核,绕过了用户态的标准IO缓冲,数据直接进入pipe,所以read可以正常读到内容。 - 你注释掉的
fsync(1)不生效的原因也很明确:fsync是针对内核态缓存的刷入操作,管不到用户态的标准IO缓冲区,调用时数据还没进入内核空间,自然不会有任何效果。
修复方案
只需要在printf调用之后新增一行fflush(stdout),强制把用户态缓冲区的数据刷入pipe对应的内核空间即可,修复后的完整代码如下:
#include <stdio.h> #include <unistd.h> const char in[7] = "qwerty"; int main () { int fds[2], stdout_sav; char str[8] = {0}; pipe(fds); if ((stdout_sav = dup(1)) < 0) return 1; // save stdout if (dup2(fds[1], 1) < 0) return 2; // stdout -> pipe close(fds[1]); if (printf(in) <= 0) return 3; fflush(stdout); // 新增行:刷入标准IO缓冲区到内核 read(fds[0], str, sizeof(in)); close(fds[0]); if (dup2(stdout_sav, 1) < 0) return 4; // restore stdout close(stdout_sav); printf("Received %s\n", str); return 0; }
编译运行后即可正常输出Received qwerty。
内容的提问来源于stack exchange,提问作者trexxet
相关产品推荐
相关产品推荐

