fork()如何工作?

时间:2013-02-27 00:55:09

标签: c fork

我真的很想分叉,这个代码中的pid是做什么的?有人可以解释一下X行和Y行的内容吗?

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE 5
int nums[SIZE] = {0,1,2,3,4};
int main()
{
    int i;
    pid_t pid;
    pid = fork();
    if (pid == 0) {
        for (i = 0; i < SIZE; i++) {
            nums[i] *= -i;
            printf("CHILD: %d ",nums[i]); /* LINE X */
        }
    }
    else if (pid > 0) {
        wait(NULL);
        for (i = 0; i < SIZE; i++)
            printf("PARENT: %d ",nums[i]); /* LINE Y */
    }
    return 0;
}

3 个答案:

答案 0 :(得分:22)

fork()重复该过程,因此在调用fork之后,实际上有2个程序实例正在运行。

您如何知道哪个进程是原始进程(父进程),哪个进程是新进程(父进程)?

在父进程中,从fork()返回子进程的PID(将为正整数)。这就是if (pid > 0) { /* PARENT */ }代码有效的原因。在子流程中,fork()只返回0

因此,由于if (pid > 0)检查,父进程和子进程将产生不同的输出,您可以看到here(由注释中的@jxh提供)。

答案 1 :(得分:15)

fork()的最简单示例

printf("I'm printed once!\n");
fork();
// Now there are two processes running one is parent and another child.
// and each process will print out the next line.
printf("You see this line twice!\n");

fork()的返回值。返回值-1 =失败; 0 =在子进程中; positive =在父进程中(返回值是子进程id)

pid_t id = fork();
if (id == -1) exit(1); // fork failed 
if (id > 0)
{ 
// I'm the original parent and 
// I just created a child process with id 'id'
// Use waitpid to wait for the child to finish
} else { // returned zero
// I must be the newly made child process
}

子进程与父进程有什么不同?

  • 当子进程结束时,将通过信号通知父进程,反之亦然。
  • 孩子不会继承待处理信号或计时器警报。有关完整列表,请参阅fork()
  • 此处可以通过getpid()返回进程ID。父进程id可以由getppid()返回。

现在让我们可视化您的程序代码

pid_t pid;
pid = fork();

现在OS制作了两个相同的地址空间副本,一个用于父级,另一个用于子级。

enter image description here

父系统和子进程都在系统调用fork()之后立即开始执行。由于两个进程具有相同但独立的地址空间,因此在fork()调用之前初始化的那些变量在两个地址空间中具有相同的值。每个进程都有自己的地址空间,因此任何修改都将独立于其他进程。如果父级更改其变量的值,则修改将仅影响父进程的地址空间中的变量。 fork()sysem调用创建的其他地址空间即使具有相同的变量名也不会受到影响。

enter image description here

这里父pid非零,它调用函数ParentProcess()。另一方面,子进程为零,它调用ChildProcess(),如下所示: enter image description here

在您的代码父进程调用wait()中,它会暂停,直到子进程退出。所以孩子的输出首先出现。

if (pid == 0) {                    
    // The child runs this part because fork returns 0 to the child
    for (i = 0; i < SIZE; i++) {
        nums[i] *= -i;
        printf("CHILD: %d ",nums[i]); /* LINE X */
    }
}

来自子流程的输出

  

第X行的内容

 CHILD: 0 CHILD: -1 CHILD: -4 CHILD: -9 CHILD: -16

然后在子进程退出之后,父进程在wait()调用之后继续,然后打印其输出。

else if (pid > 0) {
        wait(NULL);
        for (i = 0; i < SIZE; i++)
            printf("PARENT: %d ",nums[i]); /* LINE Y */
    }

来自父流程的输出:

  

Y行的内容

PARENT: 0 PARENT: 1 PARENT: 2 PARENT: 3 PARENT: 4

最后,由子进程和父进程组合的两个输出将在终端上显示如下:

 CHILD: 0 CHILD: -1 CHILD: -4 CHILD: -9 CHILD: -16 PARENT: 0 PARENT: 1 PARENT: 2 PARENT: 3 PARENT: 4

了解更多信息refer this link

答案 2 :(得分:4)

fork()函数是特殊的,因为它实际上返回两次:一次返回父进程,一次返回子进程。在父进程中,fork()返回子进程的pid。在子进程中,它返回0.如果发生错误,则不会创建子进程,并且会将-1返回给父进程。

成功调用fork()后,子进程基本上与父进程完全相同。两者都有自己的所有本地和全局变量的副本,以及它们自己的任何打开文件描述符的副本。这两个进程同时运行,并且由于它们共享相同的文件描述符,因此每个进程的输出可能会相互交错。

仔细研究问题中的例子:

pid_t pid;
pid = fork();
// When we reach this line, two processes now exist,
// with each one continuing to run from this point
if (pid == 0) {                    
    // The child runs this part because fork returns 0 to the child
    for (i = 0; i < SIZE; i++) {
        nums[i] *= -i;
        printf("CHILD: %d ",nums[i]); /* LINE X */
    }
}
else if (pid > 0) {
    // The parent runs this part because fork returns the child's pid to the parent
    wait(NULL);     // this causes the parent to wait until the child exits
    for (i = 0; i < SIZE; i++)
        printf("PARENT: %d ",nums[i]); /* LINE Y */
}

这将输出以下内容:

CHILD: 0 CHILD: -1 CHILD: -4 CHILD: -9 CHILD: -16 PARENT: 0 PARENT: 1 PARENT: 2 PARENT: 3 PARENT: 4

因为父进程调用wait(),所以它会暂停,直到子进程退出。因此孩子的输出首先出现。在孩子退出之后,父母在wait()电话之后继续,然后打印其输出。