2015-09-27 79 views
17

下面是一个Fork函数的实例。以下也是输出。我的主要问题是如何处理一个分叉被称为值如何改变。所以pid1,2和3从0开始,随着分叉的发生而变化。这是因为每次发生分叉时,值都被复制到子级,并且父级中的特定值被更改了?基本上,如何使用fork函数改变数值?C中的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? enter image description here

+2

叉子()创建一个新的过程,是可以获得父数据的副本,因为它是前叉()。另外,对fork()的调用可以有三个结果,而不仅仅是2或1(如代码所做的),结果如下:<0表示错误,= 0表示子项,> 0表示父项。代码应该总是检查所有三个结果。 I.E.这个:'pid2 = fork();/* B */ pid3 = fork();/* C * /'是错误的编码实践,因为不知道哪个进程创建'C'(实际上会有2个'C'进程)。对于进程'E'存在类似的考虑。 – user3629249

+0

儿童'B'和'C'由于前面的'if'语句,从未到达printf()语句。只有'A','D'和'E'到达printf()语句。 – user3629249

+0

youtube.com/watch?v=WcsZvdlLkPw在这个父进程有一个值被子进程ID覆盖的值是否正确? – Plisken

回答

6
int a = fork(); 

创建共享执行堆栈的重复进程“clone?”。父母和孩子之间的区别是函数的返回值。

得到0的孩子回来了,父母得到了新的pid。

每次复制堆栈变量的地址和值。执行继续到它已经在代码中的地步。

在每个fork,只有一个值被修改 - 返回值从fork

+0

所以你说的是,孩子获得父母的价值,但传回一个任意值给父母,如“1”,并改变父母的价值? – Plisken

+0

@plisken,该值是返回的孩子的进程ID。在操作系统中,它为该进程创建一个新的内存副本 - 所有文件句柄,库和分配的内存都完全相同。 OS然后将fork函数的返回值设置为新的pid,因为父级和子级的返回值都是0. fork函数是一个基元。除非您是操作系统,否则不能用C/C++编写。使用伪代码实际上并不合理。 – mksteve

+0

youtube.com/watch?v=WcsZvdlLkPw在这个父进程的值被子进程ID覆盖的值是否正确? – Plisken

2

第一至叉的一些文档(链接)

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); 
} 

以下是你的代码的一些行内注释

#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; 
} 
+0

我明白,我这样做。但看这个https://www.youtube.com/watch?v=WcsZvdlLkPw叉传递一个值到父,大概是新的进程ID。它是否正确? – Plisken

+0

是的,fork()会告诉父母pid新孩子有什么,我说过这个。请参阅“返回值”一节中提供的链接中的文档 – leakim

+0

我已阅读它我非常感谢它,它非常有帮助。但这是我最后的问题。一旦父母的价值改变与孩子进程id为什么有必要改变其他进程,就像在视频中所做的那样。 – Plisken

19

系统调用fork()用于创建进程。它不需要参数并返回进程ID。 fork()的目的是创建一个新的进程,它将成为调用者的子进程。在创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。因此,我们必须将父母与孩子区分开来。这可以通过测试fork的返回值来完成()

叉是一个系统调用,你不应该认为它是一个普通的C函数。当fork()发生时您可以有效地创建两个拥有自己地址空间的新进程。在fork()调用在地址空间中存储相同值之前进行初始化的变量。然而,在任一进程的地址空间内修改的值在其他进程中不受影响,其中一个是父进程,另一个是子进程。 所以,如果

pid=fork(); 

如果在代码的后续块你检查pid.Both的价值工艺运行代码的整个长度。那么我们如何区分它们呢? 再次叉是一个系统调用,这里是区别。在新创建的子进程中,pid将存储0,而在父进程中它将存储正值.pid中的负值表示分叉错误。

当我们测试pid 的值以找出它是否等于零或大于它时,我们正在有效地发现我们是否在子进程或父进程中。

Read more about Fork

+0

问的问题是关于这个视频。 https://www.youtube.com/watch?v=WcsZvdlLkPw为什么它会更改父级中的值? – Plisken

+0

Fork是一个系统调用。一旦你调用它,你的过程就会被复制。在子进程中,PID被设置为零,并且在父进程中,PID被赋予一个正值。现在代码的剩余部分是这两个过程是相同的(我们执行相同的代码)。因此,为了区分我们使用pid值的过程,如前所述,这是针对子&父 –

+0

youtube.com/watch?v=WcsZvdlLkPw父进程有价值被孩子进程ID覆盖的值是否正确? – Plisken