使用fork与c

这是一个学术问题,所以理由是要理解输出。

我有一个代码:

int main(int argc, char **argv) { int k ; while(*(++argv)) { k = fork(); printf("%s ",*argv); } return 0; } 

运行程序:prog ab
输出是:

  abababab 

为什么我得到这个结果?

正如Chris Lutz在评论中所建议的那样,您正在观察由fork()调用复制的printf使用的静态缓冲区的效果。 由第一个fork()创建的两个进程不打印b (正如您所料,并且如果强制刷新则会发生)。 它们都打印ab因为它们在各自的缓冲区中都有待处理的未刷新的a

有4个进程(2 ^ 2,包括初始进程),它们只在刷新缓冲区时才真正在出口处打印,并且它们在那时都在各自的缓冲区中都有ab

在开始时, argv将指向argv[0] ,它是可执行文件名,它在内部增加, while()指向argv[1]

现在它命中fork()创建从同一行开始的第二个线程。

两个线程都会将a写入自己的stdout缓冲区。

现在argv在两个实例中移动了1个字符(在while()内部,因为如果我没记错的话,它们基本上可以使用副本。

每个线程中的fork现在将创建2个额外的线程副本(每个现有线程一个)。

现在4个实例都将在复制的stdout缓冲区中保留’a’(如果有人能证实这一点,那就很好),并且他们的argv指向b 。 这个也写了,所以现在我们有4个线程,每个线程的输出缓冲区都有’ab’。

一旦它们结束,它们的缓冲区就会被刷新,从而产生’abababab’(基本上是’ab’,’ab’,’ab’和’ab’)。

Ben的评论可以通过换行引起的冲洗来解释。

我不知道“fork”,但我可以告诉你,在循环的第二次迭代中,你正在访问一个无意义的内存区域。 这肯定会返回损坏的,毫无意义的结果,更糟糕的是,它可能会破坏程序的执行。

当然,你应该这样做

while ((--argc) >= 0) { (...) }

如果你不需要知道循环后argc的原始值,或者

 int i = 0; while (i++ < argc) { (...) } 

首先,终端是行缓冲的,即在遇到换行符时刷新缓冲区。 如果在printf()中添加换行符,则结果会发生变化。 但是,如果要写入完全缓冲的文件,即使将换行符添加到printf(),输出也不会发生变化。

在第一次fork()调用之后,P(父)有’a’而C1也有’a’。 (C为孩子)。

然后,在第二次fork调用之后,创建两个新子节点C2和C3。 过程的缓冲区也被复制,因此C2和C3现在也包含’a’。 在printf()调用之后,所有进程在其缓冲区中都包含“ab”。 当它们退出时,它们的缓冲区被刷新,因此输出。