将打印多少XD?

时间:2014-10-16 06:26:46

标签: c linux buffer stdout


当我和我的一个朋友一起玩fork()时,我遇到了这个奇怪的问题。 非常简单的POC代码喜欢:

int main(int argc, char** argv)
{
    int i = 0;
    for(i=0; i<4; i++) {
        printf("xd\n");
        fork();
    }
    return 0;
}

我得到了一个漂亮的输出: xd xd xd xd xd xd xd xd xd xd xd xd xd xd xd xd已被打印15次,这是我所期望的 - 4级完整二叉树中的节点数。 但是,当我们删除&#34; \ n&#34;在printf中,我们得到了另一个完全不同的结果:

xdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxdxd

它给了我64个XD(我的朋友在他的机器上有56个XD)。这似乎有点'稳定'#34;结果,因为我可以多次运行它,它给我相同的结果(与我的朋友相同)。

我尝试将printf(&#34; xd&#34;)更改为perror(&#34; xd&#34;),它给了我15个输出: xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success xd: Success 我试过了

    for(i=0; i<4; i++) {
        printf("xd");
        fflush(stdout);
        fork();
    }

这将在一行中给我15个XD。
我敢打赌这与输出缓冲区有关,但我无法解释这一点。
我有两个天真的猜测,一个是将其视为经典并发问题,但我很快就否认它,因为fork()创建另一个进程而不是线程,每个子进程实际上持有i的不同副本。 (如果我错了,请纠正我)
另一个天真的猜测是,当多个进程写入同一个stdout时,就在缓冲区中的内容显示在屏幕上但之前已从缓冲区清除之前,如果另一个进程将某些内容写入缓冲区,它将停止清理它/将整个缓冲区视为有效。
这两个都很可能是错误的,因为我对Linux实现知之甚少,有人可以帮我解释一下吗?

2 个答案:

答案 0 :(得分:2)

您关注的行为是因为缓冲模式。

因为最后没有换行符,并且输出以行缓冲模式运行(或者 全缓冲模式)这就是为什么你看到的输出是不同的

在分叉之前必须使用fflush(0);清空所有I / O缓冲区

您可以通过标准C函数setvbuf()_IOFBF(完全缓冲),_IOLBF(行缓冲)和_IONBF(无缓冲)来控制缓冲模式模式。

答案 1 :(得分:1)

stdout是linebuffered,因此在第一个版本中,所有printf将立即打印出来:

i=0: 1 xd
i=1: 2 xd
i=2: 4 xd
i=3: 8 xd
in sum: 15 xd
另一边没有\n stdout缓冲区的

将每fork()复制一次,因此将xd计数加倍。

i=0:  1 xd, after fork  2 xd and  2 processes
i=1:  4 xd, after fork  8 xd and  4 processes
i=2: 12 xd, after fork 24 xd and  8 processes
i=3: 32 xd, after fork 64 xd and 16 processes

在主过程结束时,将打印所有64 xd。