← 返回首页
Linux高级程序设计(二十八)
发表时间:2021-11-16 22:07:40
fork函数

fork函数是非常重要的函数,它的作用是从已经存在的进程中创建一个子进程,而原进程称为父进程。

函数原型:

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

失败的两个主要原因是: 1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。 2)系统内存不足,这时 errno 的值被设置为 ENOMEM。

实例:

#include <stdio.h>  
#include <sys/types.h>  
#include <unistd.h>

int main(int argc, char const *argv[]){
    //注意:执行了fork函数就会在原有进程上创建一个子进程,而fork之后不区分父子进程代码区。后面所有的代码都会执行。
    fork();
    printf("hello,world!"); 
    while(1){
    }
    return 0;
}

测试运行:

hello,world!
hello,world!

注意:window下没有一个函数可以实现UNIX下的fork()函数,其原因是历史造成的.对于UNIX来说它一出生就是多用户的系统,所以它的所有进程都共有一个最原始的父进程init.而windows生下来时是个单用户系统(DOS),不存在这样的概念.所以fork这个函数是UNIX下特有的。因此以上代码也只能在linux环境下运行。

我们通过fork函数的返回值来区分父子进程的代码块。 实例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int pid = fork();
    if (pid < 0)
    {
        perror("erro to create process:");
    }

    if (pid > 0)
    {
        //这里是父进程代码块
        while (1)
        {
            printf("I am father pid=%d,ppid=%d\n",getpid(),getppid());
            printf("I am father!\n");
            printf("pid = %d\n",pid);
            sleep(1);
        }
    }
    else
    {
        //这里是子进程代码块
        while (1)
        {
            printf("I am son pid=%d,ppid=%d\n",getpid(),getppid());
            printf("I am son!\n");
            sleep(1);
        }
    }
    return 0;
}

测试运行:

[root@iz2zefozq9h39txdb8s7npz shelldemo]# ./a.out
I am father pid=13535,ppid=13023
I am father!
pid=13536
I am son pid=13536,ppid=13535
I am son!
I am father pid=13535,ppid=13023
I am son pid=13536,ppid=13535
I am father!
pid=13536

注意:这里父子进程是按照时间片交替执行,并不是父进程执行完之后执行子进程。一般来说,在 fork() 之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。

使用 fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信息)。因此,使用 fork() 函数的代价是很大的。

简单来说,一个进程调用 fork() 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

为验证父子进程各自的地址空间是独立的,看下面实例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int a = 100; // 全局变量
int main(int argc, char *argv[])
{
    int b = 200;        //局部变量
    static int c = 300; //静态变量
    int pid;
    pid = fork();

    if (pid < 0)
    { 
        //没有创建成功
        perror("error to create process:");
    }

    if (pid > 0)
    {
        //父子进程
        a++;
        b++; 
        c++;
        printf("father: a = %d, b = %d, c=%d\n", a, b, c);
    }
    else
    {
        //子进程
        sleep(1); // 保证父进程先运行,但不保证1秒足够
        printf("son: a = %d, b = %d,c=%d\n", a, b, c);
    }

    while(1){
    }
    return 0;
}

测试运行:

[root@iz2zefozq9h39txdb8s7npz shelldemo]# ./a.out
father: a = 101, b = 201, c=301
son: a = 100, b = 200,c=300