fork是什么

C语言中的函数,fork在英文中是分叉的意识,在C语言中,执行过fork的进程会分叉出一个新的进程。

新进程被成为子进程,原来的进程被称为父进程。

fork的功能

这里举两个例子说明一下fork的功能

例子1
//fork.c
    
#include <unistd.h>
#include <stdio.h>

int main(void)
{
   int i = 0;
   fork();
   i++;
   printf("i = %d \n", i);

}
gcc -o fork fork.c
./fork
i = 1 
i = 1
分析

程序在执行到fork的时候克隆出了子进程,子进程具有当前进程的一切资源。

子进程从fork开始执行,并不执行fork前面的代码。

fork之后的代码有两个进程在执行,因此输出了两次。

而且fork之后父子进程不共享数据,因此两边数据不互相影响,一开始i=0,i++之后i都等于1。

同时由于父子进程不共享数据,因此父子进程要通信只能通过进程间通信


例子2

该段代码来源于其他博客

#include <unistd.h>
#include <stdio.h>
int main(void)
{
    int i = 0;
    printf("i son/pa ppid  pid   fpid\n");
    //ppid指当前进程的父进程pid
    //pid指当前进程的pid,
    //fpid指fork返回给当前进程的值
    for (i = 0; i < 2; i++)
    {
        pid_t fpid = fork();
        if (fpid == 0)
            printf("%d child  %4d %4d %4d\n", i, getppid(), getpid(), fpid);
        else
            printf("%d parent %4d %4d %4d\n", i, getppid(), getpid(), fpid);
    }
    return 0;
}
./fork2
i son/pa ppid  pid   fpid
0 parent 5973  31644 31645
0 child  31644 31645    0

1 parent 5973  31644 31646
1 parent 31644 31645 31647
1 child  31644 31646    0
1 child  31645 31647    0
分析

for循环执行了两次,第一次执行fork变成两个进程,第二次执行fork变成四个进程。

在父进程中fork执行的返回值是子进程pid,在子进程中为0。因此子进程执行else段代码,父进程执行if段代码。

第一次循环:

在这里插入图片描述

第二次循环

在这里插入图片描述

在第二次循环中,31645变成了父进程,它也创建了对应的子进程。

因为第一次循环有两个进程,第二次循环有四个进程,每个进程执行一次输出。所以最后输出了2+4=6行。

总结
  • fork的返回值有三种

    • 0:子进程返回0
    • 大于0:父进程返回子进程pid
    • -1:创建失败
  • fork一次调用会返回两次

  • 程序执行fork后会产生子进程,子进程具有父进程的一切资源,父子进程同时执行。

  • 父子进程不共享数据

fork的使用场景

可以应用在服务器中,服务器在接收到连接请求的时候可以fork出进程来处理新的连接请求,父进程等待下一个连接请求到达。

fork的原理

fork在创建进程的时候,把内核中的task_struct(每个进程在内核中都是task_struct结构)复制了一份,还创建了新的进程地址空间和堆栈。父子进程除了极少数不一样之外,其他都一样。

父子进程使用的内存实际上是同一个物理内存,实际上是共享的。

但是共享的内存被内核设置成了只读,因此不会出现问题。

如果有一方尝试写入,就会触发异常机制,内核发现异常之后会分配一个新的空间让父子进程分开使用,这个过程就叫做写时拷贝机制。

一个进程可以有多个线程,但是fork复制时只会复制当前的一个线程。

这是历史遗留问题,早期进程都是单线程的,这样fork没有问题,但是到了多线程时代,fork的技术依然没有改进。

参考

这里是一篇fork的趣味解说

Logo

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

更多推荐