注:本次学习代码所用编程所用语言为C语言
在Linux中我们使用fork()函数进行进程创建, 该函数包含在<unistd.h>中。

1. 父进程与子进程:

fork()函数创建的进程为子进程。
调用fork()函数的进程称父进程。

2. fork()函数:

pid_t fork(viod)
// pid_t 相当于int类型

调用fork()函数过后, 系统会创建一个与原进程几乎相同的进程(感觉就像是将父进程的程序代码复制了一份给子进程),然后父子进程都继续往下执行。
fork()函数调用成功后它能返回两个值,因为如果调用成功,父进程的代码就会复制给子进程,这样也就有了两个fork()函数,所以返回两个值。父进程的fork()函数返回值是子进程的pid, 子进程的fork()函数返回值是0。若进程创建失败,则原进程不会被复制, 返回值为-1。

fork()函数创建进程实例一:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    pid_t pid = 0;   
    pid = fork();    //创建进程
    if(pid == -1){          //fork()返回值为-1,调用失败
        perror("fork error.\n");
        exit(-1);
    }
    else if(pid > 0){
        printf("parent process, pid = %d, ppid = %d.\n", getpid(), getppid());     //getpid():获取当前进程的进程号
    }
    else if(pid == 0){            //fork()返回值为0,则该进程是子进程
        printf("child process, pid = %d, ppid = %d.\n", getpid(), getppid());           // getppid():获取父进程的进程号
    }
    printf("------------finish--------------\n");
    return 0;

}

代码运行结果:
在这里插入图片描述

从上述结果可以看到,我们调用fork()函数创建了一个子进程,子进程的pid为6911。这里区分我们代码中的pid与子进程的进程号, 代码中的pid是我们调用fork()函数的返回值, 而进程号是我们用getpid()获取的进程的进程号。
fork()函数创建进程成功后,父进程和子进程分别执行,直观体现是上述代码执行后,打印输出了两次finish。

思考:

当我们多次执行上述代码后会发现这样一个问题:child process输出的ppid不等于父进程的pid, 这是什么原因?

这是因为创建的子进程优先级和父进程一样, 两者争夺资源,当父进程先获得cpu资源后,会比子进程先运行完毕,此时子进程变成了孤儿进程,由父进程的父进程或者init进程进程进行回收。

fork()创建多进程实例二:

现在我们想要调用fork()函数创建多个进程,应该怎么实现呢?大多数人的第一想法可能是用for循环。那么我们就用for循环来试一下。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    pid_t pid = 0;
    int i = 0;
    for(i = 0; i<3; i++){
        pid = fork();
    }
    if(pid == -1){
        perror("fork error.\n");
        exit(-1);
    }
    else if(pid > 0){
        printf("parent process, pid = %d, ppid = %d\n", getpid(), getppid());
    }
    else if(pid == 0){
        printf("child process, pid = %d, ppid = %d\n", getpid(), getppid());
    }
    printf("------------finish--------------\n");
    return 0;

}

代码与实例一相比就是将创建进程的地方改成了for循环。我们设置的是循环三次, 我们期待的结果是创建三个子进程, 加上父进程,一共四个进程。但是我们来看一下结果:
在这里插入图片描述
finish一共打印了八次, 说明我们创建了七个进程。这是怎么回事呢?

原因分析:

我们用fork()函数创建进程的时候, 是将父进程的代码复制了一份给子进程,那么显然在子进程中依然存在for循环中创建进程的语句fork()这个语句, 子进程也会执行该语句创建新的进程, 直到循环结束。所以我们最终创建进程的数量书2**n - 1个。

解决方案:

我们就是想要只创建我们循环里执行个数的子进程,我们可以让子进程不能执行创建进程的语句。加一个判断条件,当这个进程是子进程的时候, 我们就跳出循环,不进行创建进程。怎么判断该进程是子进程呢?fork()函数的返回值为0时, 该进程时子进程。

改进方案:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    pid_t pid = 0;
    int i = 0;
    for(i = 0; i<3; i++){
        if((pid = fork()) == 0)
            break;
    }
    if(pid == -1){
        perror("fork error.\n");
        exit(-1);
    }
    else if(pid > 0){
        printf("parent process, pid = %d, ppid = %d\n", getpid(), getppid());
    }
    else if(pid == 0){
        printf("child process, pid = %d, ppid = %d\n", getpid(), getppid());
    }
    printf("------------finish--------------\n");
    return 0;

}
运行结果:

在这里插入图片描述
可见,只创建了三个子进程。

思考:

为什么子进程的进程号不是递增的?

这是因为子进程的优先级是一样的,所及获得系统资源。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐