我正在创建一个多进程程序。当我尝试使用if(f == 0) break;
在for循环中调用fork()时。我得到了所需数量的子进程。
但是现在,我正在处理输入文件,并且最初不知道所需的进程数。这是我的代码中最小的可能示例。
FILE* file = fopen("sample_input.txt", "r");
while(fscanf(file, "%d", &order) == 1){
f = fork();
if(f == 0){
break;
}
}
示例sample_input.txt
:
5 2 8 1 4 2
现在正在创建数千个子进程(我想要6,文件中的整数),可能是什么原因?它与文件指针有关吗?
编辑:我使用控制台输出进行了一些调试,子进程确实打破了循环。但是,父母一直在阅读一个小文件。如果我删除fork()
,循环将按预期执行6次。
编辑2:我有一个理论,我无法证明你可以帮助我。可能是这样的情况:文件指针在进程之间共享,当子进程退出时,它关闭文件,当父进程再次尝试读取时,它只是从头开始(或其他一些奇怪的行为)。可能是这样吗?
答案 0 :(得分:10)
当第一个进程读取第一个数字时,它实际上将整行读入内存。过程分叉。
子进程打破了循环;接下来发生的事情没有指定,但可能会退出。父进程现在读取第二个数字并再次分叉。同样,孩子退出,父母读取第三个数字,叉子等。
在读取第六个数字并退出第六个子节点后,父节点将从文件中读取另一个缓冲区。在Linux上(或者更准确地说,使用GNU C库),您会得到一些奇怪的效果。请参阅Why does forking my process cause the file to be read infinitely?中的讨论以查看详细信息。但是,退出的子项会将文件描述符的读取位置调整回到开头,因此父级可以再次读取更多数据。
我对另一个问题的回答显示,如果子进程在退出之前关闭文件,则不会发生此行为。 (无论如何不应该发生,但根据经验确实如此。)
GLIBC Bug 23151 - 带有未关闭文件的分叉进程在退出之前会执行lseek,并且会导致父I / O中出现无限循环。
该错误创建于2019-05-08美国/太平洋地区,并于2018-05-09关闭为无效。给出的理由是:
请阅读 http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01, 尤其是这一段:
请注意,在
fork()
之后,存在两个句柄,其中之前存在一个句柄。 [...]
请参阅Why does forking my process cause the file to be read infinitely?对此进行广泛讨论。
答案 1 :(得分:0)
读取文本文件中每个字符的次数等于创建的进程数。进程总数= 2n,其中n是fork系统调用的数量。所以这里n = 3,2 ^ 3 = 8
让我们为这三行添加一些标签名称:
fork (); // Line 1
fork (); // Line 2
fork (); // Line 3
L1 // There will be 1 child process
/ \ // created by line 1.
L2 L2 // There will be 2 child processes
/ \ / \ // created by line 2
L3 L3 L3 L3 // There will be 4 child processes
// created by line 3
示例:
int main()
{
fork();
fork();
fork();
printf("Gwapo ko\n");
return 0;
}
输出:
Gwapo ko
Gwapo ko
Gwapo ko
Gwapo ko
Gwapo ko
Gwapo ko
Gwapo ko
Gwapo ko
检查另一个例子:
void forkexample()
{
// child process because return value zero
if (fork()==0)
printf("Hello from Child!\n");
// parent process because return value non-zero.
else
printf("Hello from Parent!\n");
}
int main()
{
forkexample();
return 0;
}
输出:
1.
Hello from Child!
Hello from Parent!
(or)
2.
Hello from Parent!
Hello from Child!
创建子进程,fork()在子进程中返回0,将正整数返回到父进程。 这里有两个输出,因为父进程和子进程同时运行。因此,我们不知道操作系统是否首先控制父进程或子进程将关闭的进程。
重要说明:父进程和子进程正在运行相同的程序,但这并不意味着它们是相同的。操作系统为这两个过程分配不同的数据和状态,并且控制这些过程的流程也可以不同。
理论:关闭的流程可能是一个子流程,而不是父流程,而是父流程和其他子流程。