猿问

在Linux gcc中fork()的工作

fork() 创建一个新进程,子进程从父进程的当前状态开始执行。


这是我fork()在Linux中了解的事情。


因此,相应地,以下代码:


int main() {

  printf("Hi");

  fork();

  return 0;

}

根据上述,只需打印一次“ Hi”即可。


但是在用gcc编译的Linux上执行上述操作时,它会两次打印“ Hi” 。


有人可以向我解释使用中实际发生了什么fork(),如果我理解fork()正确的工作原理吗?


青春有我
浏览 548回答 3
3回答

狐的传说

当您将某些内容打印到“标准输出”标准输出(通常是计算机监视器,尽管您可以将其重定向到文件)时,它最初会存储在临时缓冲区中。分叉的两面都继承未刷新的缓冲区,因此,当分叉的每一面触及return语句并结束时,都会刷新两次。在分叉之前,应该fflush(stdout);先刷新缓冲区,以使子代不会继承该缓冲区。屏幕上的stdout(而不是将其重定向到文件时)实际上是由行尾缓冲的,因此,如果您这样做了printf("Hi\n");,则不会有此问题,因为它会刷新缓冲区本身。

拉莫斯之舞

printf("Hi");并不会立即在屏幕上显示“ Hi”一词。它所做的是在stdout缓冲区中填充单词“ Hi”,一旦缓冲区“被刷新”,该字词就会显示出来。在这种情况下,stdout指向您的显示器(假定)。在这种情况下,缓冲区将在缓冲区已满,强制您刷新或(最常见)打印换行符(“ \ n”)时刷新。由于在fork()调用时缓冲区仍然充满,因此父进程和子进程都继承该缓冲区,因此在刷新缓冲区时,它们都将打印出“ Hi”。如果fflush(stout);在调用fork之前先调用,它应该可以工作:int main() {  printf("Hi");  fflush(stdout);  fork();  return 0;}另外,正如我所说,如果您在其中包含换行符,printf那么它也应该可以正常工作:int main() {  printf("Hi\n");  fork();  return 0;}

温温酱

通常,在fork()两侧的库中使用开放的句柄/对象是非常不安全的。这包括C标准库。fork()使两个进程合二为一,没有库可以检测到它的发生。因此,如果两个进程继续使用相同的文件描述符/套接字等运行,它们现在将具有不同的状态,但共享相同的文件句柄(从技术上讲,它们具有副本,但具有相同的基础文件)。这使坏事发生。fork()导致此问题的情况的示例stdio,例如tty输入/输出,管道,光盘文件数据库客户端库使用的套接字服务器进程使用的套接字-当为一个套接字提供服务的孩子碰巧继承了文件的句柄时,可能会产生奇怪的效果-正确地进行这种编程是很棘手的,请参阅Apache的源代码示例。在一般情况下如何解决此问题:要么a)在fork()之后,可能立即在同一二进制文件上调用exec()(带有必要的参数以完成您打算做的任何工作)。这很容易。b)分叉之后,请勿使用任何依赖于它们的现有打开的句柄或库对象(可以打开新的句柄);尽快完成工作,然后调用_exit()(而不是exit())。不要从调用fork的子例程中返回,因为那样可能会导致调用C ++析构函数等,这可能会对父进程的文件描述符造成不良影响。这相当容易。c)分叉之后,在让孩子继续之前,以某种方式清理所有物体并使它们都处于健全状态。例如,关闭基础文件描述符,而不刷新父缓冲区中重复的缓冲区中的数据。这很棘手。c)大约是Apache所做的。
随时随地看视频慕课网APP
我要回答