07-管道和stdio缓冲
44.6 管道和stdio缓冲
由于popen()调用返回的文件流指针没有引用一个终端,因此stdio库会对这种文件流应用块缓冲(参见13.2节)。这意味着当将mode的值设置为w来调用popen()时,在默认情况下只有当stdio缓冲器被充满或使用pclose()关闭了管道之后输出才会被发送到管道另一端的子进程。在很多情况下,这种处理方式是不存在问题的。但如果需要确保子进程能够立即从管道中接收数据,那么就需要定期调用fflush()或使用setbuf(fp, NULL)调用禁用stdio缓冲。当使用pipe()系统调用创建管道,然后使用fdopen()获取一个与管道的写入端对应的stdio流时也可以使用这项技术。
如果调用popen()的进程正在从管道中读取数据(即mode是r),那么事情就不是那么简单了。在这样情况下如果子进程正在使用stdio库,那么——除非它显式地调用了fflush()或setbuf()——其输出只有在子进程填满stdio缓冲器或调用了fclose()之后才会对调用进程可用。(如果正在从使用pipe()创建的管道中读取数据并且向另一端写入数据的进程正在使用stdio库,那么同样的规则也是适用的。)如果这是一个问题,那么能采取的措施就比较有限的,除非能够修改在子进程中运行的程序的源代码使之包含对setbuf()或fflush()调用。
如果无法修改源代码,那么可以使用伪终端来替换管道。一个伪终端是一个IPC通道,对进程来讲它就像是一个终端。其结果是stdio库会逐行输出缓冲器中的数据。第64章将会介绍伪终端。