3 回答
TA贡献1804条经验 获得超3个赞
当您将某些内容打印到“标准输出”标准输出(通常是计算机监视器,尽管您可以将其重定向到文件)时,它最初会存储在临时缓冲区中。
分叉的两面都继承未刷新的缓冲区,因此,当分叉的每一面触及return语句并结束时,都会刷新两次。
在分叉之前,应该fflush(stdout);
先刷新缓冲区,以使子代不会继承该缓冲区。
屏幕上的stdout(而不是将其重定向到文件时)实际上是由行尾缓冲的,因此,如果您这样做了printf("Hi\n");
,则不会有此问题,因为它会刷新缓冲区本身。
TA贡献1820条经验 获得超10个赞
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;
}
TA贡献1752条经验 获得超4个赞
通常,在fork()两侧的库中使用开放的句柄/对象是非常不安全的。
这包括C标准库。
fork()使两个进程合二为一,没有库可以检测到它的发生。因此,如果两个进程继续使用相同的文件描述符/套接字等运行,它们现在将具有不同的状态,但共享相同的文件句柄(从技术上讲,它们具有副本,但具有相同的基础文件)。这使坏事发生。
fork()导致此问题的情况的示例
stdio,例如tty输入/输出,管道,光盘文件
数据库客户端库使用的套接字
服务器进程使用的套接字-当为一个套接字提供服务的孩子碰巧继承了文件的句柄时,可能会产生奇怪的效果-正确地进行这种编程是很棘手的,请参阅Apache的源代码示例。
在一般情况下如何解决此问题:
要么
a)在fork()之后,可能立即在同一二进制文件上调用exec()(带有必要的参数以完成您打算做的任何工作)。这很容易。
b)分叉之后,请勿使用任何依赖于它们的现有打开的句柄或库对象(可以打开新的句柄);尽快完成工作,然后调用_exit()(而不是exit())。不要从调用fork的子例程中返回,因为那样可能会导致调用C ++析构函数等,这可能会对父进程的文件描述符造成不良影响。这相当容易。
c)分叉之后,在让孩子继续之前,以某种方式清理所有物体并使它们都处于健全状态。例如,关闭基础文件描述符,而不刷新父缓冲区中重复的缓冲区中的数据。这很棘手。
c)大约是Apache所做的。
- 3 回答
- 0 关注
- 547 浏览
添加回答
举报