fork总结

本文详细解析了fork函数的作用及特性,包括其如何创建新进程、调用与返回机制、父子进程间资源分配的区别,并通过三个实例演示了fork的实际运作过程。

fork作用

fork可以用来创建一个新的进程。

fork声明

这里写图片描述

fork特性

  1. fork调用一次,返回两次:
    1)返回0给子进程
    2)返回子进程的进程ID给父进程
  2. 父子进程的先后执行顺序是不确定的,这个取决于内核的调度算法
  3. 子进程只是父进程的一份拷贝,子进程会复制父进程的数据空间、堆、栈。它们不会共享这部分内容,只会共享正文段(正文段,可以把它理解成一块专门存储代码的内存)

下面通过三个例程来说明fork的特性

demo1

      1 void demo1(void)                                                                                                                  
      2 {
      3     pid_t pid;
      4     int val = 0;
      5     
      6     if( (pid=fork()) < 0)
      7     {
      8         printf("fork fail\n");
      9     }   
     10     else if(0 == pid)       // This is children process
     11     {
     12         val = 50;
     13         printf("This is children, parent pid:%d, current pid:%d, pid:%d\n", getppid(), getpid(), pid);
     14     }   
     15     else                   // This is parent process
     16     {
     17         val = 100;
     18         printf("This is parent, parent pid:%d, current pid:%d, pid:%d\n", getppid(), getpid(), pid);
     19     }   
     20     
     21     printf("pid:%d, val:%d\n", getpid(), val);
     22 } 

程序运行的结果如下

This is parent, parent pid:2908, current pid:3164, pid:3165
pid:3164, val:100
This is children, parent pid:1, current pid:3165, pid:0
pid:3165, val:50

分析demo1的代码和运行结果

从运行结果看,第13行的打印输出了,而且第18行的打印输出了,平时我们看到的code,一般if和else只会跑其中一个,但是这里跑了两次。说明fork调用一次,返回两次,所以else if(0 == pid)和else这两种情况都会跑进去。

从代码和运行结果看,打印显示父进程中pid:3165,子进程中current pid:3165, pid:0 ,fork之后,有两个返回值,返回0给子进程,返回子进程的ID给父进程。

运行结果显示的是先打印parent,再打印children,但是这个打印是不确定的,有可能是先打印children,再打印parent。有的人可能会想,如果我在parent打印前加个sleep(1)或者spleep多秒,这样是不是就保证了children会先打印呢?这个不好说,即使在parent打印前sleep多秒,系统还是有可能先打印children,这个要根据系统的调度算法。

从运行结果看,parent和children的val值都是自己最先设定的值,这说明了子进程只是父进程的一个拷贝,子进程将父进程的数据空间、堆、栈都拷贝了一份,而不是共享。所以这里val的值大家互不干涉。

demo2

  1 void demo2(void)                                                                                                                   
  2 {
  3     printf("l1\n");
  4     fork();
  5     printf("l2\n");
  6     fork();
  7     printf("l3\n");
  8 }   

程序运行的结果如下

l1
l2
l3
l2
l3
l3
l3

分析demo2的代码和运行结果

程序跑到第3行的时候,会打印出l1

当程序跑到第4行fork之后,会创建出一个父进程A和一个子进程B,因为子进程是父进程的一份拷贝。也就是说,父子进程都会包含剩下的正文段(代码),即都包含第5行到第8行的代码。那么,接下来,父子进程都会跑第5行的代码,也就是各自打印出l2

接下来,主要讲父进程A怎么跑的,因为父子进程跑的内容是一样的。程序运行到第6行的时候,又fork了一次,父进程A里又创建了一个父进程C和子进程D,父(C)子(D)进程都包含第7行代码,所以父进程(C)和子进程(D)都会打印出l3.

因为父进程A和子进程B执行的是一样的内容,所以父进程A创建的进程C和进程D,会打印出两个l3,子进程B也是一样会打印出两个l3.

可以通过下图更直观地了解,打印的顺序看具体的系统调度算法。
这里写图片描述

demo3

  1 void demo3(void)                                                                                                                  
  2 {
  3     printf("l1\n");
  4     fork();
  5     printf("l2\n");
  6     fork();
  7     printf("l3\n");
  8     fork();
  9     printf("l4\n");
 10 }

程序运行的结果如下

l1
l2
l3
l2
l4
l3
l4
l3
l4
l4
l4
l3
l4
l4
l4

分析demo3的代码和运行结果

其实demo3和demo2很像,刚开始都会打印出l1,遇到第一个fork,就会创建一个父进程A和子进程B,进程A和B都会拷贝第5行到第9行的代码

那么接下来父(A)子(B)进程都会打印出l2,遇到第二个fork,父(A)子(B)进程各自都会创建新的父子进程,以此类推,直接用图来表示

这里写图片描述

### Fork 的概念及其在编程和版本控制中的应用 #### 编程中的 Fork `fork()` 是 Unix 和类 Unix 操作系统中用于创建新进程的一个重要函数。调用 `fork()` 函数时,当前进程会复制自己并生成一个新的子进程[^1]。这个过程可以被描述为:父进程通过调用 `fork()` 创建了一个几乎完全相同的副本——即子进程。父子进程之间的主要区别在于它们的 PID(Process ID),以及返回值的不同。 - **返回值** - 对于父进程而言,`fork()` 返回的是子进程的 PID。 - 子进程中,`fork()` 则返回 0。 - 如果发生错误,则返回 `-1` 表示失败。 下面是一个简单的 C 代码示例展示如何使用 `fork()`: ```c #include <stdio.h> #include <unistd.h> int main() { pid_t pid = fork(); // 调用 fork() if (pid == 0) { printf("Child Process: My PID is %d\n", getpid()); } else if (pid > 0){ printf("Parent Process: Child's PID is %d\n", pid); } else { perror("Fork failed"); } return 0; } ``` 此程序展示了基本的父子进程关系,并打印各自的 PID 值来区分两者。 需要注意的是,在某些硬件环境下实现高效内存分配存在困难的情况下,标准 POSIX 定义还提供了像 `vfork()` 这样的替代方案作为补充选项之一[^3]。 #### 版本控制系统中的 Fork 另一方面,“fork”一词也广泛应用于软件开发领域特别是基于 Git 或其他分布式版本控制系统的工作流程里。“Forking repository”指的是开发者从原始仓库派生出自己的独立分支来进行修改或者实验而不影响原项目[^2]。这种做法常见于开源协作模式下当个人希望提交补丁给上游维护者之前先在一个分离的空间完成初步工作后再发起 pull request 请求合并更改到官方主线之中去。 例如,在 GitHub 平台上执行如下操作即可轻松获得一份属于您自己的远程拷贝以便自由编辑而无需担心破坏源码库结构: 1. 访问目标存储库页面; 2. 单击右上方 “Fork” 按钮; 3. 自动跳转至您的账户下的克隆版地址链接处; 之后就可以按照常规方式 clone 下载下来本地继续后续处理步骤啦! 总结起来看,无论是操作系统层面还是现代互联网服务架构设计思路当中都离不开对资源隔离机制的研究探讨,而这其中就包含了我们今天所提到这两个不同维度却同样重要的技术知识点:“fork”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值