c - 使用跨叉继承的 stdio.h FILE * 流有哪些缺陷?

标签 c fork posix system-calls stdio

我写了一个(简单的)包装器,它在子进程中执行另一个进程 过程。子进程在调用 exec() 之前关闭(或重定向)标准错误。但是,如果 exec() 失败,我希望在父进程的标准错误上打印一条错误消息。

以下是我目前的解决方案。我在 fork 之前 dup()licate 标准错误。 因为我希望能够进行格式化的 I/O,所以我在复制的对象上调用了 fdopen() 处理。 (我知道,就目前而言,这个程序毫无意义,但我有 只保留了我的问题的相关部分。)

#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;
}

我现在的问题是:使用FILE *变量log有哪些陷阱, 在父进程和子进程中?我读过 IEEE Std 1003.1-2008 标准,XSH,Sections 2.5 and 2.5.1 (“文件描述符和标准 I/O 流的交互”),据我所知,这应该可行,除了我可能需要在 fork 之前添加 fflush(log) 如果标准错误碰巧被缓冲了。那是对的吗?还有其他需要注意的陷阱吗?

此外,同一标准在第 2.5 节中指出

The address of the FILE object used to control a stream may be significant; a copy of a FILE object need not necessarily serve in place of the original.

我是否可以认为这意味着通过 fork() 继承的 FILE 对象是安全的 有什么用?

我应该补充一点,我不打算在父进程之间做任何事情 fork() 和 wait()。

最佳答案

除了在 fork 之前需要 fflush 之外,您还应该考虑标准错误可能不是控制台/管道,而是常规文件的情况。

如果您从两个文件描述符写入一个常规文件(这就是您的 parent 和 child 现在拥有的),写入可能会相互重叠。如果发生这种情况,您可能会丢失信息。

我建议使用fcntl(F_SETFL) 来确保文件描述符处于O_APPEND 模式。在那种模式下,两个进程可以写入同一个文件而不会相互覆盖。

即使在 O_APPEND 中,如果写入太大,输出也可能重叠。由于您使用的是缓冲 IO(FILE* 是什么),这不太可能,但并非不可能。此时你最好的选择就是捕获这个机会,并且相对频繁地 fflush,这样发送到 write 的缓冲区就不会太大。

关于c - 使用跨叉继承的 stdio.h FILE * 流有哪些缺陷?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46417749/

相关文章:

c - POSIX 计时器在运行几次后挂起

c - setpgid 的竞争条件

c - 从用户输入获取shell命令并执行C程序

linux - 程序如何获取 sigwaitinfo() 返回的 siginfo_t 结构中的消息队列描述符

c - 在 C 中使用指针通过引用修改数组

c - 从小测试文件切换到 31 mb 文件时出现 SegFault

linux - 在 Valgrind/DrMemory 中记录程序状态然后恢复是否可行?

c - vfork 永不返回

c - sprintf - 它实际上做了什么

c - 使用 Makefile 取消定义预处理器变量