C 使用通过fork继承的stdio.h FILE*流有哪些陷阱?
我编写了一个(过于简单的)包装器,它在子进程中执行另一个进程 过程子进程在调用exec()之前关闭(或重定向)标准错误。但是,如果exec()失败,我希望在父进程的标准错误上打印一条错误消息 下面是我目前的解决方案。我在fork之前复制标准错误。 因为我希望能够进行格式化I/O,所以我对复制的文件调用fdopen() 手柄(我知道,就目前情况而言,这个计划没有什么意义,但我知道 只保留了我问题的相关部分。)C 使用通过fork继承的stdio.h FILE*流有哪些陷阱?,c,fork,posix,system-calls,stdio,C,Fork,Posix,System Calls,Stdio,我编写了一个(过于简单的)包装器,它在子进程中执行另一个进程 过程子进程在调用exec()之前关闭(或重定向)标准错误。但是,如果exec()失败,我希望在父进程的标准错误上打印一条错误消息 下面是我目前的解决方案。我在fork之前复制标准错误。 因为我希望能够进行格式化I/O,所以我对复制的文件调用fdopen() 手柄(我知道,就目前情况而言,这个计划没有什么意义,但我知道 只保留了我问题的相关部分。) #包括 #包括 #包括 #包括 #包括 int main(int argc,char*a
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
智力状态;
文件*log=fdopen(dup(2),“w”);
开关(fork()){
案例1:
fprintf(日志,“fork:%s\n”,strerror(errno));
打破
案例0:
关闭(2);
execvp(argv[1],&argv[1]);
fprintf(日志,“execvp:%s\n”,strerror(errno));
打破
违约:
等待(&状态);
打破
}
返回0;
}
我现在的问题是:使用文件*
变量日志
,有哪些陷阱,
在父进程和子进程中?我读过IEEE标准1003.1-2008
Standard,XSH(“文件描述符和标准I/O流的交互”),据我所知,这应该是可行的,但如果碰巧缓冲了标准错误,我可能需要在fork之前添加fflush(log)
。对吗?还有其他陷阱需要注意吗
同样,该标准在第2.5节中规定:
用于控制流的文件对象的地址可能是重要的;
文件对象的副本不必代替
原创的
我可以认为这意味着通过fork()继承的文件
对象是安全的吗
使用
我应该补充一点,我不打算在两人之间的家长流程中做任何事情
FoK()和WaIT().< P>除了在Fo耙之前需要<代码> FFLUSS,还应该考虑标准错误可能不是控制台/管道,而是常规文件的情况。 如果您从两个文件描述符(您的父级和子级现在都有)写入常规文件,则写入操作可能会相互重叠。如果发生这种情况,您可能会丢失信息 我建议使用
fcntl(F_SETFL)
来确保文件描述符处于O_APPEND
模式。在这种模式下,两个进程可以写入同一个文件,而不会相互覆盖
即使在O_APPEND中,如果写入太大,输出也可能重叠。由于您使用的是缓冲IO(这就是
文件*
的含义),所以这种可能性较小,但并非不可能。在这一点上,你最好的办法是抓住这个机会,也要经常使用<代码> FFLUSS,这样发送到fcntl(F_SETFL)
来确保文件描述符处于O_APPEND
模式。在这种模式下,两个进程可以写入同一个文件,而不会相互覆盖
即使在O_APPEND中,如果写入太大,输出也可能重叠。由于您使用的是缓冲IO(这就是
文件*
的含义),所以这种可能性较小,但并非不可能。在这一点上,你最好的办法就是抓住这个机会,并且相对频繁地进行fflush
,这样发送到write
的缓冲区就不会太大。你可能还想看看(默认情况下,stderr
不会被缓冲)我发现了一个我在中分析过的非常特殊的情况。TL;DR-是的,您希望fflush
fork之前的每个共享流-包括输入流。请注意,刷新输入流的行为仅在POSIX.1-2008中指定…@Edward我的问题是关于使用文件流的安全性(或不安全性)。密切关注执行官是高度相关的<基于代码>文件的流构建在标准文件描述符之上。如果流下面的文件描述符设置了FD_CLOEXEC
标志,则该描述符将在exec()
上关闭,并且文件
流将以危险的方式无效-用于文件
的文件描述符值可用于其他用途,导致流以静默方式访问完全不同的内容。有很多原因可以解释为什么在这里避免stdio I/O和使用低级POSIX I/O是一个更好的选择。就我个人而言,在这种情况下,我在write()
周围使用了一个非常简单的包装器(还使用fcntl()
来标记重复的描述符O_CLOEXEC
,这样它就不会对新的可执行文件保持打开状态)。这种方法还允许将代码移植到Mac OS X,在Mac OS X中,fork()
和exec()
之间的环境有点局限于异步信号安全函数。使用是另一种选择(在POSIX.1-2008中),用于使用低级I/O,但我不清楚是哪个C库实现了它。您可能还想看看(默认情况下,stderr
不缓冲)太长了,读不下去了,我发现了一个非常奇怪的角落案例,我分析了。Tr.Dr-是的,你想在Fooff[#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
int status;
FILE *log = fdopen(dup(2), "w");
switch (fork()) {
case -1:
fprintf(log, "fork: %s\n", strerror(errno));
break;
case 0:
close(2);
execvp(argv[1], &argv[1]);
fprintf(log, "execvp: %s\n", strerror(errno));
break;
default:
wait(&status);
break;
}
return 0;
}