C中的fork()函数
Posted
技术标签:
【中文标题】C中的fork()函数【英文标题】:Fork() function in C 【发布时间】:2015-12-24 23:40:11 【问题描述】:下面是 Fork 函数的示例。下面也是输出。我的主要问题与叉子有关,称为如何更改值。所以 pid1,2 和 3 从 0 开始,并随着分叉的发生而改变。这是因为每次分叉发生时,值都会被复制到子级并且父级中的特定值会发生变化?基本上值如何随 fork 函数变化?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
pid_t pid1, pid2, pid3;
pid1=0, pid2=0, pid3=0;
pid1= fork(); /* A */
if(pid1==0)
pid2=fork(); /* B */
pid3=fork(); /* C */
else
pid3=fork(); /* D */
if(pid3==0)
pid2=fork(); /* E */
if((pid1 == 0)&&(pid2 == 0))
printf("Level 1\n");
if(pid1 !=0)
printf("Level 2\n");
if(pid2 !=0)
printf("Level 3\n");
if(pid3 !=0)
printf("Level 4\n");
return 0;
然后这就是执行。
----A----D--------- (pid1!=0, pid2==0(as initialized), pid3!=0, print "Level 2" and "Level 4")
| |
| +----E---- (pid1!=0, pid2!=0, pid3==0, print "Level 2" and "Level 3")
| |
| +---- (pid1!=0, pid2==0, pid3==0, print "Level 2")
|
+----B----C---- (pid1==0, pid2!=0, pid3!=0, print nothing)
| |
| +---- (pid1==0, pid2==0, pid3==0, print nothing)
|
+----C---- (pid1==0, pid2==0, pid3!=0, print nothing)
|
+---- (pid1==0, pid2==0, pid3==0, print nothing)
理想情况下,下面是我希望看到的解释方式,因为这种方式对我来说很有意义。 * 是我的主要困惑所在。例如,当孩子分叉pid1 = fork();
时,它创建了一个包含父进程所有值的进程,但它是否会传递一个值,比如让我们说 1 给父进程 pid1?这意味着孩子将有 pid 1=0、pid2=0 和 pid3=0,而父母则为 pid1=2 和 pid2 和 3 等于 0?
【问题讨论】:
fork() 创建一个新进程,该进程获取父数据的副本,就像在 fork() 之前一样。此外,对 fork() 的调用可以产生三个结果,而不仅仅是 2 或 1(正如代码所做的那样),三个结果是:0 表示父项。代码应始终检查所有三个结果。 IE。这:pid2=fork(); /* B */ pid3=fork(); /* C */
是不好的编码习惯,因为不知道哪个进程创建了“C”(实际上会有 2 个“C”进程)进程“E”也存在类似的考虑
子 'B' 和 'C' 永远不会到达 printf() 语句,因为之前的 'if' 语句。只有 'A'、'D' 和 'E' 会到达 printf() 语句。
youtube.com/watch?v=WcsZvdlLkPw 在此父进程的值被子进程 ID 覆盖,这是正确的吗?
【参考方案1】:
我认为您创建的每个进程都开始执行您创建的行,所以像这样......
pid=fork() at line 6. fork function returns 2 values
you have 2 pids, first pid=0 for child and pid>0 for parent
so you can use if to separate
.
/*
sleep(int time) to see clearly
<0 fail
=0 child
>0 parent
*/
int main(int argc, char** argv)
pid_t childpid1, childpid2;
printf("pid = process identification\n");
printf("ppid = parent process identification\n");
childpid1 = fork();
if (childpid1 == -1)
printf("Fork error !\n");
if (childpid1 == 0)
sleep(1);
printf("child[1] --> pid = %d and ppid = %d\n",
getpid(), getppid());
else
childpid2 = fork();
if (childpid2 == 0)
sleep(2);
printf("child[2] --> pid = %d and ppid = %d\n",
getpid(), getppid());
else
sleep(3);
printf("parent --> pid = %d\n", getpid());
return 0;
//pid = process identification
//ppid = parent process identification
//child[1] --> pid = 2399 and ppid = 2398
//child[2] --> pid = 2400 and ppid = 2398
//parent --> pid = 2398
linux.die.net
some uni stuff
【讨论】:
【参考方案2】:系统调用 fork() 用于创建进程。它不接受任何参数并返回一个进程 ID。 fork() 的目的是创建一个新进程,该进程成为调用者的子进程。创建新的子进程后,两个进程都将执行 fork() 系统调用之后的下一条指令。因此,我们必须区分父母和孩子。这可以通过测试 fork() 的返回值来完成
Fork 是一个系统调用,你不应该把它当作一个普通的 C 函数。当 fork() 发生时您有效地创建了两个具有自己地址空间的新进程。在 fork() 调用之前初始化的变量在两个地址空间中存储相同的值。但是,在任一进程的地址空间内修改的值在其他进程中不受影响,其中一个是父进程,另一个是子进程。 所以如果,
pid=fork();
如果您在随后的代码块中检查 pid 的值。两个进程都会运行整个代码长度。那么我们如何区分它们。 Fork 是一个系统调用,这里有区别。在新创建的子进程中,pid 将存储 0,而在父进程中它将存储一个正值。pid 中的负值表示 fork 错误。
当我们测试 pid 的值时 找出它是等于零还是大于它,我们实际上是在找出我们是在子进程还是父进程中。
Read more about Fork
【讨论】:
Fork 是一个系统调用。只要你调用它。你的进程是重复的。在子进程中,pid 设置为零,在父进程中,pid 被赋予正值。现在两个进程的代码的剩余部分是相同的(我们正在执行相同的代码)。因此,为了区分我们使用 pid 值的进程,如前所述,子进程和父进程是分开的 youtube.com/watch?v=WcsZvdlLkPw 在此父进程的值被子进程 ID 覆盖,这是正确的吗? 请告诉我视频让您感到困惑的时间!我无法浏览我所知道的 7 分钟视频教程 youtube.com/… 在进行了 2 次分叉后,他进行了第三次分叉,因为他在第二次分叉中更改了一个值。【参考方案3】:首先是一些 fork() 文档的链接
http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html
pid 由内核提供。每次内核创建一个新进程时,它都会增加内部 pid 计数器并为新进程分配这个新的唯一 pid,并确保没有重复。一旦 pid 达到某个较高的数字,它将重新包装并重新开始。
所以你永远不知道你会从 fork() 中得到什么 pid,只有父进程会保持它的唯一 pid,而 fork 会确保子进程将有一个新的唯一 pid。上面提供的文档中对此进行了说明。
如果您继续阅读文档,您将看到 fork() 为子进程返回 0,并且子进程的新唯一 pid 将返回给父进程。如果孩子想知道它自己的新 pid,您必须使用 getpid() 查询它。
pid_t pid = fork()
if(pid == 0)
printf("this is a child: my new unique pid is %d\n", getpid());
else
printf("this is the parent: my pid is %d and I have a child with pid %d \n", getpid(), pid);
以下是您代码中的一些内联 cmets
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
pid_t pid1, pid2, pid3;
pid1=0, pid2=0, pid3=0;
pid1= fork(); /* A */
if(pid1 == 0)
/* This is child A */
pid2=fork(); /* B */
pid3=fork(); /* C */
else
/* This is parent A */
/* Child B and C will never reach this code */
pid3=fork(); /* D */
if(pid3==0)
/* This is child D fork'ed from parent A */
pid2=fork(); /* E */
if((pid1 == 0)&&(pid2 == 0))
/* pid1 will never be 0 here so this is dead code */
printf("Level 1\n");
if(pid1 !=0)
/* This is always true for both parent and child E */
printf("Level 2\n");
if(pid2 !=0)
/* This is parent E (same as parent A) */
printf("Level 3\n");
if(pid3 !=0)
/* This is parent D (same as parent A) */
printf("Level 4\n");
return 0;
【讨论】:
我明白,我明白。但是请注意这个youtube.com/watch?v=WcsZvdlLkPw,fork 将一个值传递给父进程,大概是新的进程 id。这是正确的吗? 是的,这是真的,fork() 会告诉父母新孩子有什么 pid,我说了这一点。另请参阅“返回值”部分下提供的链接中的文档 我已经阅读了我非常感谢它非常有帮助。但这是我的最后一个查询。一旦使用子进程 ID 更改了父值,为什么有必要像视频中所做的那样更改其他进程。【参考方案4】:int a = fork();
创建一个重复的进程“克隆?”,它共享执行堆栈。父子的区别在于函数的返回值。
得到 0 的子进程返回,父进程得到新的 pid。
每次复制堆栈变量的地址和值。在代码中已经到达的位置继续执行。
在每个fork
,只有一个值被修改——来自fork
的返回值。
【讨论】:
所以你的意思是,孩子获得了父母的值,但将任意值传回给父母,例如“1”,这会改变父母的价值? @plisken,该值是返回的子进程的进程 ID。在操作系统中,它为进程创建一个新的内存副本——所有文件句柄、库和分配的内存都完全相同。然后操作系统将 fork 函数的返回值设置为新的 pid,因为父进程和子进程的返回值都是 0。fork 函数是一个原语。除非你是操作系统,否则它不能用 C/C++ 编写。想出伪代码真的没有意义。 youtube.com/watch?v=WcsZvdlLkPw 在此父进程的值被子进程 ID 覆盖,这是正确的吗? @Plisken “覆盖”是返回值。它描述了x = function(); /* change the value of x */
不修改父级的任何内部状态时的变化除了fork输出的返回值
我明白了,谢谢。最后一个查询youtube.com/…你能告诉我他为什么第三次分叉吗?他做了 2 次,在第二次分叉后,他不得不再次从第一次分叉。这是为什么?以上是关于C中的fork()函数的主要内容,如果未能解决你的问题,请参考以下文章
子进程是否从 Fork 函数 后 开始执行,执行函数后的代码。Fork函数之前的不执行?
linux C语言 clone() 和 fork() 的区别,fork函数的用法,主要应用场景(clone是fork的升级版本,可以将创建出来的进程变成父进程的兄弟进程)
在 C 编程中,如何 fork() 在子进程中运行 N 个函数调用?