登录
首页 >  文章 >  linux

Linux父子进程fork机制深度解析

时间:2025-05-04 18:57:27 266浏览 收藏

在Linux系统中,进程是操作系统最重要的执行单元,而父子进程的创建与管理是系统资源分配和任务并行的关键。通过fork函数,Linux能够快速高效地复制一个进程,使得父子进程协同工作成为可能。本文详细解析了Linux父子进程的运行特性、fork的核心机制及其在实际开发中的应用,帮助读者掌握系统编程的核心技能,并为优化资源利用与提高程序性能提供理论基础。

前言

在Linux系统中,进程是操作系统最重要的执行单元,而父子进程的创建与管理更是系统资源分配和任务并行的关键。通过fork函数,Linux能够快速高效地复制一个进程,使得父子进程协同工作成为可能。理解父子进程的运行机制不仅有助于掌握系统编程的核心技能,更能为优化资源利用与提高程序性能提供理论基础。本文将带你从基础原理出发,解析Linux父子进程的运行特性、fork的核心机制及其在实际开发中的应用。


一、进程PID

PID 是用来唯一标识一个进程的属性,我们可以使用 ps 指令查看一个进程的部分属性。进程的属性信息是由操作系统来维护的,这些信息被存储在一个 task_struct 结构体中,属于操作系统内核中的数据。由于操作系统本身是不相信用户的,所以用户无法直接去访问 task_struct 对象中的成员,因此 ps 指令能够显示进程的属性信息,本质上是通过系统调用接口去实现的。

1.1 通过系统调用接口查看进程PID

获取进程的 PID 需要用到系统调用接口 getpid() ,该函数会返回调用该函数的进程的 PID,返回值类型为 pid_t 。如下图我们使用 man getpid 指令去查看 getpid 的基础文档:

父子进程的故事:解读Linux中的fork机制在这里插入图片描述

注意上图中还有一个 getppid 是什么呢?不难猜到,这应该是用来获取父进程 PID 的系统调用接口,接下来我们写段代码来具象化 PID 吧。 注意上图中还有一个 getppid 是什么呢?不难猜到,这应该是用来获取父进程 PID 的系统调用接口,接下来我们写段代码来具象化 PID 吧。

代码语言:javascript代码运行次数:0运行复制
在这里插入图片描述

进程的 PCB 对象会找到相应的代码和数据,然后 CPU 就要去调度这个进程,也就是找到该进程的代码和数据去执行。调用 fork 函数创建子进程,本质上是操作系统多了一个进程,因此 fork 函数创建出来的子进程,它要先创建自己的 PCB 对象,子进程的 PCB 对象大部分都是以父进程的 PCB 对象为模板创建的,即从父进程的 PCB 对象中拷贝过来,再对部分属性稍作修改,子进程的 PCB 对象就有了。但是它没有自己的代码和数据,所以只能用父进程的,所以 fork 函数之后,父子进程的代码共享,这就解释了为什么上面 fork 函数之后的代码输出了两次,其实就是父子进程各自执行了一次。

创建子进程的目的就是为了帮助父进程做不同的事情,但是父子进程共享一份代码,所以我们应该在代码中对它们加以区分。fork 函数就帮我们完成了这个需求,它会在父子进程中返回不同的值,用户只需要根据返回值的不同让父子进程执行不同的代码。 fork 函数的实现过程:

创建子进程创建子进程的PCB填充PCB对应的内容让子进程和父进程指向同样的代码此时父子进程都有独立的task_struct对象,可以被CPU调度运行了return ret;

由于父子进程会共享一份代码,所以在 fork 函数执行 return 语句之前,子进程的 PCB 对象就已经被创建出来了,CPU 已经可以去同时调度父子进程。由于 fork 函数中的 return 语句也是被共享的,所以 fork 函数有两个返回值。

2.4 一个变量怎么会有不同的内容?1. fork 的返回值如何写入不同的变量空间

当调用 fork 时,父进程与子进程会各自接收一个返回值,并且写入同名变量 id。但这并不意味着他们共享同一块内存,而是因为:

独立的进程地址空间 每个进程都有自己独立的虚拟地址空间。在 fork 之后,父进程与子进程的地址空间是彼此独立的。尽管子进程初始时看起来与父进程完全相同,但实际上它们的数据是分离的。写时拷贝(COW)机制 操作系统为提高效率并节省资源,采用了写时拷贝技术。在 fork 之后: 父子进程共享同一份内存数据,直到有一方尝试修改这些数据。当某个进程试图修改数据时,操作系统会为该进程分配新的物理内存空间,并将被修改的数据复制到新分配的空间中。2. fork 中变量 id 的本质

在代码中,变量 id 是存储 fork 返回值的地方。以下几点解释了为什么同名变量可以存储不同的值:

父子独立运行 fork 返回后,父子进程的执行路径分开。父进程的 id 变量存储的是子进程的 PID,而子进程的 id 变量存储的是 0。不同的内存空间 由于父子进程的地址空间独立,id 实际上存在于两块不同的内存区域,即父进程的 id 和子进程的 id 是完全独立的变量。赋值过程 fork 的返回值通过操作系统写入到父子进程各自的 id 变量中: 父进程在 return 时向 id 写入子进程的 PID。子进程在 return 时向 id 写入 0

结语

Linux父子进程的运行机制展示了操作系统设计的高效性与灵活性。从fork的返回值设计到写时拷贝(COW)的优化方案,这一切都体现了Linux在性能与资源利用上的巧妙平衡。通过深入理解父子进程的特性,不仅能够提升系统编程的能力,还能为并发和并行程序设计提供坚实的理论支持。希望本文能为你的学习和实践带来启发,在Linux系统的探索中迈向更高的层次。

父子进程的故事:解读Linux中的fork机制在这里插入图片描述

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,17的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是17前进的动力!

终于介绍完啦!小伙伴们,这篇关于《Linux父子进程fork机制深度解析》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

最新阅读
更多>
课程推荐
更多>
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    立即学习 542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    立即学习 508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    立即学习 497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    立即学习 487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    立即学习 484次学习