使用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”。 当它们退出时,它们的缓冲区被刷新,因此输出。