我有一个简单的程序:
int main()
{
std::cout << " Hello World";
fork();
}
程序执行后,我的输出是:Hello World Hello World
。为什么不是一个单独的Hello world
?我猜测子进程在后台重新运行,并且输出缓冲区在进程间共享,或者发生了其他事情,但这是否是真的呢?
这并不是你最初想象的那样。输出缓存区不是共享的 - 当您执行fork时,两个进程都会获得相同缓冲区的副本。因此,在fork之后,两个进程最终会单独刷新缓冲区并将内容分别打印到屏幕上。
这仅在使用缓冲IO的cout时发生。如果您使用未缓冲的cerr,则应该只看到一条消息,即fork之前。
标准输出使用缓存IO。当调用 fork()
时,标准输出不会被刷新,缓冲内容会被复制到子进程中。这些缓冲区在进程退出时才会被刷新,导致你看到两个输出。
如果你将程序改为:
std::cout << " Hello World;" << std::endl;
你应该只看到一个。
因为您在调用fork()之前没有先刷新所有缓冲区。
cout.flush();
fork();
输出"Hello World"
的代码只会执行一次。问题在于输出缓冲区没有被清空。所以当你fork进程后,"Hello World"
仍然留存在输出缓冲区中。当两个程序退出时,它们的输出缓冲区将被清空,你将看到输出两次。
最简单的方法是在字符串末尾添加一个换行符,这将导致隐式刷新,或者使用std::cout.flush();
显式刷新。然后你只会看到一次输出。
std::cout << " Hello World" << std::flush;
您只看到了一个输出。我猜测fork()
会复制std::cout
写入的任何输出缓冲区。
字符串不会立即写入屏幕,而是写入内部缓冲区。子进程继承输出缓冲区的副本,因此当子进程的cout
自动刷新时,Hello World
将被打印到屏幕上。父进程也会打印Hello World
。
如果在fork()
之前刷新cout
,问题几乎肯定会消失。
原因是当您调用std::cout<<
时,它并没有真正执行输出,而是将数据留在系统的缓冲区中。当您执行fork时,代码和数据以及所有相关的缓冲区都会被复制。最后,父进程和子进程都会将它们刷新到标准输出中,因此您会看到输出重复。
fork()
的问题……嗯…… - Mysticial