你能解释fflush()和重定向输出在这里发生了什么吗?

2 c multithreading

所以我写了一个测试程序,这里是代码

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int i;
    printf("%s", "entering\n");
    fflush(stdout);
    for (i = 0 ; i < 3 ; i++)
    {
        fork();
        fflush(stdout);
    }

    printf("%s", "exiting\n");
}
Run Code Online (Sandbox Code Playgroud)

当我在终端中编译并运行它时,它会显示我所期望的:"进入"一次,"退出"一些.当我运行它并将输出重定向到文件时,它会显示每个退出的输入.

1)为什么每次都不向终端和文件输出相同的东西?

2)为什么它显示8次输入文件但没有在终端输入一次(一次是我期望它做的).

3)当我的输出转到文件时,fflush()语句会有所不同吗?

pax*_*blo 5

它与标准文件句柄上的缓冲有关.从ISO C99 7.19.3/7 Files:

最初打开时,标准错误流未完全缓冲; 当且仅当可以确定流不参考交互设备时,标准输入和标准输出流被完全缓冲.

当您写入终端时,输出很可能是(a)行缓冲,这意味着只要发送换行符就会刷新它.

通过重定向,它是完全缓冲的,这意味着它只会在缓冲区满时才会刷新.

您可以setvbuf在操作之前使用stdout,将其设置为无缓冲或行缓冲,您不必担心刷新.

setvbuf (stdout, NULL, _IONBF, BUFSIZ); // _IONBF for  no  buffering.
                                        // _IOFBF for full buffering.
                                        // _IOLBF for line buffering.
Run Code Online (Sandbox Code Playgroud)

请记住,如果您将输出发送到文件,无缓冲输出可能会影响性能.另请注意,对此的支持是实现定义的,不受标准保证.

C99第7.19.3/3节是相关位:

当流未缓冲时,字符应尽快从源或目的地出现.否则,可以将字符作为块累积并发送到主机环境或从主机环境发送.

当流被完全缓冲时,当填充缓冲区时,字符将作为块传输到主机环境或从主机环境传输.

当流被行缓冲时,当遇到换行符时,字符将作为块传输到主机环境或从主机环境传输.

此外,当填充缓冲区,在无缓冲流上请求输入时,或者在需要从主机环境传输字符的行缓冲流上请求输入时,字符旨在作为块传输到主机环境. .

对这些特性的支持是实现定义的,并且可能通过setbufsetvbuf函数受到影响.


(a)标准未指定标准输入和输出是无缓冲的还是行缓冲的,其中基础文件可能是交互式的(参见此处).线路缓冲是我遇到的最常见的(到目前为止).


至于为什么你得到多条entering消息,即使你在分叉之前刷新它,这是一个更棘手的问题.你没有列出你的环境,所以这是最好的假设,但我看到了一些可能性(虽然可能会有更多).

首先,fflush由于某种原因,可能会失败.这实际上是可行的,但很容易检查,因为它的行为类似于write(因为它通常在封面下调用 write).

换句话说,errno在冲洗后检查是否存在问题.如果是这样,C运行时缓冲区仍将在所有子节点中刷新,因此它们都将写入entering.

其次,即使刷新了缓冲区,也可能在下面(在该write级别或在终端驱动程序本身内)进行更多缓冲,这些缓冲由其复制fork,从而导致到终端的多个输出.我认为这不太可能.

第三,这可能只是一个奇怪的平台特定问题.当我在Ubuntu 11.04盒子上运行你的代码时,我发现终端输出和文件输出变体之间没有区别.它们都输出一条entering和八条exiting消息.

如果第三个是这种情况那么你真的没有追索权:ISO C并没有强制要求在这种情况下发生的事情,因为ISO C一无所知fork.我在POSIX.1中找不到任何似乎表明这种或那种方式的东西,但它可能存在.

对于它的价值,如果我只注释掉第一个fflush,我会得到entering两次,然后是八条exiting消息.如果我只评论第二个,它就像它们在那里一样,一个entering接着是八个exiting.

如果我评论他们两个,我得到八entering/exiting对.