我是 POSIX 世界的新手,我试图了解 fork 系统调用在 C 中的工作原理,特别是它如何在父级到子级之间复制文件描述符和缓冲区。具体来说这两种情况:
案例一: 我有一个简单的程序可以打印一些东西
printf "start"
fork
parent:
print something
child
print something
这最终会打印“start”一次,然后打印父块和子块。这意味着 fork 在复制 I/O 缓冲区之前先刷新它们。
案例2: 相同的程序,但现在我正在写入文件而不是标准输出。 该文件导致开始打印两次,这对我来说很奇怪。 fork 是否只刷新标准缓冲区而不刷新文件缓冲区?
用于测试的程序:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
int main() {
pid_t pid;
FILE *fd;
// Open a file in writing mode
fd = fopen("filename.txt", "w");
// Write some text to the file
fprintf(fd, "Started\n");
// Create a child process
pid = fork();
if (pid < 0) {
// Fork failed
fprintf(stderr, "Fork failed\n");
fclose(fd);
return 1;
} else if (pid == 0) {
// This is the child process
const char *child_message = "Hello from the child process!\n";
fprintf(fd, child_message);
fclose(fd); // Close the file descriptor in the child process
exit(0);
} else {
// This is the parent process
const char *parent_message = "Hello from the parent process!\n";
fprintf(fd, parent_message);
// Wait for the child process to complete
wait(NULL);
// Write a final message from the parent
const char *completion_message = "Child process completed.\n";
fprintf(fd, completion_message);
fclose(fd); // Close the file descriptor in the parent process
}
return 0;
}
首先,
fork()
不会刷新缓冲区。
其次,牢记这两点
当且仅当输出流连接到终端设备时,它始终是行缓冲的。比如
stdout
和stderr
,都是这种情况。否则输出流将被完全缓冲。
fork()
将所有内存从父级复制到子级。 (为了降低复杂性,我们不在这里讨论COW
)
现在回到你的问题。
在您的第一个示例中,只有一个“开始 打印出",是因为在
fork()
之前,stdout
的缓冲区已经被flush了(行缓冲),复制到子进程时缓冲区已经空无一物了。
在第二个示例中,两个“开始 ” 被打印。这是因为在
fork()
之前,常规文件的缓冲区还没有被刷新(完全缓冲)。包含“Start
" 被复制到子进程。