【Linux】fork入门级使用

news2024/9/24 22:46:43

目录

 一、前置准备

1、进程的基本概念

2、进程标识符PID、PPID

1)pid介绍

2)获取pid和ppid

二、fork函数

1、fork的基本介绍

1)fork(): 创建子进程

2)对于函数具体的描述

3)两个返回值

2、感受一下fork的使用

3、子进程的作用?-->实现不同于父进程的功能

4、创建的子进程如何存储,PCB都是如何确定的?-->子进程(PCB单独创建)和父进程共享代码和数据

5.为什么fork要有两个返回值?

6.为什么fork要给子进程返回0,给父进程返回子进程pid?

7.fork之后,父子进程谁先运行?

7.一个变量怎么会有不同的内容?-->地址空间


全文在Ubuntu 20.04.6 LTS的环境下使用C语言!

本篇文章需要大家具备一定的Linux的基础下,进行学习~

 一、前置准备

1、进程的基本概念

【Linux】进程周边:进程概念-CSDN博客

这篇文章中已经将进程的基础概念、进程控制块PCB、查看进程的基本信息、杀掉进程,进行了介绍~

稍后本篇也会提及到部分内容。

2、进程标识符PID、PPID

1)pid介绍

进程标识符:pid

  • task_struct里面的一个变量
  • 当前操作系统中每个进程的唯一性标识

PPID:当前进程的父进程的标识符

获取 进程(pid) 的函数:getpid();
获取 父进程(ppid) 的函数:getppid();

进程的pid都是独一无二的,每次运行程序,都相当于一个新的进程,所以每启动一次程序,该进程的pid就会变化,但是父进程的PID不会变。(也就是无论孩子怎么变化,他的父亲该是谁,就是还是谁!)
在命令行运行的命令或程序都是bash的子进程;
几乎所有的指令都是程序,运行起来都是进程;

2)获取pid和ppid

  • #include <sys/types.h>
  • #include <unistd.h>
  •  pid_t getpid(void);
  •  pid_t getppid(void);

通过man 手册查询getpid()的使用。

man getpid

获取 进程(pid) 的函数:getpid();
获取 父进程(ppid) 的函数:getppid();

二、fork函数

1、fork的基本介绍

我们先来看看Linux系统中对于fork函数是怎么介绍的!

使用man指令查询

man fork

可见:

1)fork(): 创建子进程

2)对于函数具体的描述

  • fork()通过复制调用进程来创建一个新进程。
  • 新进程被称为子进程。调用进程被称为父进程。
  • 子进程和父进程在单独的内存空间中运行。
  • 子进程几乎是父进程的完全拷贝(某些情况例外)

3)两个返回值

如果成功,则在父进程中返回子进程的PID,并在子进程中返回0。
如果失败,则在父进程中返回-1,不创建子进程,并适当设置errno

这就是fork的特性,具有两个返回值!

2、感受一下fork的使用

让我们根据以下代码,对于fork的使用进一步了解。

我们希望这段代码能够达到,

创建进程之后,

父进程可以输出自己的pid、以及自己对应的父进程的pid、还有fork子进程的pid

子进程可以输出自己的pid、以及自己对应的父进程的pid、还有返回值0

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

int main()
{
    printf("创建子进程前,这只有一个进程,pid:%d,ppid:%d\n",getpid(),getppid());

    sleep(3);//休眠3秒
    //我们创建进程,感受父子进程
    printf("创建新的进程了\n");

    pid_t id = fork();//接收返回值

    //利用条件选择语句,区分父、子进程
    //id = 0 --> 当前进程是子进程
    //id = 子进程的pid  -->那么当前进程是父进程
    if(id == 0)
    {
        //子进程
        while(1){
            printf("after fork, 我是子进程: I am a prcess, pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);//休眠1秒,避免刷新太快
        }
    }
    else{
        //父进程
         while(1){
            printf("after fork, 我是父进程: I am a prcess, pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);
        }

    }

    return 0;
}

具体的pid变化过程:

父子进程可以执行不同的任务

通过上面的代码,可以看到父、子进程可以利用条件选择if else同时执行不同的内容。

那么,子进程就可以做一些父进程不能做,又或是不敢做的事情,这样既不会危害到父进程,也能完成任务。


通过上文的代码实现,我们可以对fork又有了进一步的了解。那么对于fork,又会引发对应的问题.

首先,子进程究竟有什么作用?

以及创建的子进程的存储和进程信息都是如何确定的?

为什么fork要有两个返回值?

为什么fork要给子进程返回0,给父进程返回子进程pid?

父子进程怎么实现执行的不同的内容


3、子进程的作用?-->实现不同于父进程的功能

通过上面的代码和图文,可以发现fork之前的代码只有父进程执行
然而fork之后的代码父子进程都要执行

创建子进程的意义就是
为了让子进程执行和父进程不一样的代码,实现和父进程不一样的功能。

比如我们可以一边下载聊天,一边播放音乐,这两个过程就是不同的进程在执行!



那修改一下功能,

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

int main()
{
    printf("创建子进程前,这只有一个进程,pid:%d,ppid:%d\n",getpid(),getppid());

    sleep(3);//休眠3秒
    //我们创建进程,感受父子进程
    printf("创建新的进程了\n");

    pid_t id = fork();//接收返回值

    //利用条件选择语句,区分父、子进程
    //id = 0 --> 当前进程是子进程
    //id = 子进程的pid  -->那么当前进程是父进程
    if(id == 0)
    {
        //子进程
        while(1){
            printf("after fork, 我是子进程,正在播放视频: pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);//休眠1秒,避免刷新太快
        }
    }
    else{
        //父进程
         while(1){
            printf("after fork, 我是父进程,正在进行聊天: pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);
        }

    }

    return 0;
}

可以查看图片,确实父子进程分别在 实现不同的功能。

4、创建的子进程如何存储,PCB都是如何确定的?-->子进程(PCB单独创建)和父进程共享代码和数据

fork会创建子进程,系统中会多出一个子进程。

操作系统以父进程为模板,为子进程创建PCB,但是子进程中是没有代码和数据的,所以子进程和父进程共享代码和数据
所以fork之后,父子进程会执行一样的代码。

5.为什么fork要有两个返回值?

  • 返回不同的返回值,是为了 区分父、子
  • 为了让fork以后的if、while等条件判断语句进行区分,来让父子进程执行 不同 的代码片段
  • 两个进程可以执行不同的功能(进程之间是相互独立的)

最重要的也是因为,

fork执行过程中,

子进程被创建完毕,自然就会会执行父进程中的代码和数据,自然也会执行到return这一句。

因此,父子都会返回一个数值,产生了两个返回值。

以下,是fork函数执行的大概逻辑!!

可以发现,在fork函数return之前,
就已经创建了子进程,并且将子进程放入调度队列中运行了,

所以当子进程,在调度队列时,它和父进程就已经分流了


而不是真正在fork函数return之后才分流的

并且创建完子进程后代码是共享的,在fork以后的代码执行了两次
很明显return也是一句代码。

所以父子进程,都会执行return语句,fork函数有两个返回值

部分内容参考这个篇文章:【linux进程(二)】如何创建子进程?--fork函数深度剖析_linux系统用for循环创建三个子进程-CSDN博客

6.为什么fork要给子进程返回0,给父进程返回子进程pid?

  • 一个进程只能有一个父进程,但是可以拥有多个子进程。
  • 一个父进程可以创建很多个子进程,然而一个子进程只对应一个父进程,所以fork函数会返回子进程的pid给父进程,方便父进程对于子进程进行管理。

7.fork之后,父子进程谁先运行?

创建完成子进程后,这只是一个开始,系统的其他进程,父进程,子进程接下来会被调度执行!

问题是先调度谁?先创建就先调度吗?

答案明显不是!不能确定谁先执行。

在调度队列中,CPU会选择一个进程去运行它,谁先被调度,谁就先运行!

所以fork之后父子进程谁先运行,用户是不确定的,这是由各自进程PCB中的调度信息决定的,比如优先级,算法信息等等       

8.一个变量怎么会有不同的内容?-->地址空间

我们继续使用一开始的代码。

在这段代码中,可以看到,if  else两个都被执行了,也就是说,id这个变量满足两个不同的条件。-----> id这个变量有两个值。

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

int main()
{
    printf("创建子进程前,这只有一个进程,pid:%d,ppid:%d\n",getpid(),getppid());

    sleep(3);//休眠3秒    
    printf("创建新的进程了\n");

    pid_t id = fork();//接收返回值
    if(id == 0)
    {
        //子进程
        while(1){
            printf("after fork, 我是子进程: pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);
        }
    }
    else{
        //父进程
         while(1){
            printf("after fork, 我是父进程:pid: %d, ppid: %d, return id: %d\n\n", getpid(), getppid(), id);
            sleep(1);
        }

    }

    return 0;
}

但是同一个变量怎么可能有两个不同的值呢?

进程是有独立性的。
首先是表现在进程各自的PCB运行时不会相互影响。

很明显,代码本身只是可读的,所以不会影响代码。

但是对于数据来说,父子的数据是可能不同的(可能会被修改)

所以系统是怎样做到让数据在各个进程都自己私有一份的?

答案是写时拷贝(类似于学习类和对象时的深浅拷贝数据会在需要使用时,被写时拷贝到PCB。)
然而fork返回值赋值给变量时,本质也是写入,返回时也会发生写时拷贝,所以不同
的进程执行的代码中的变量id获取的值不同!

父、子进程空间分配的文章

linux多进/线程编程(2)—— fork函数和进程间“共享”数据 - 胖白白 - 博客园 (cnblogs.com)

进程专题02篇———进程共享(读时共享写时复制copy-on-write)原理详解——超经典-CSDN博客

深入学习fork的文章推荐:

【创建进程】fork函数与写时拷贝-阿里云开发者社区

fork()写时复制原理-阿里云开发者社区

参考文章:

【Linux系列】fork( )函数原理与应用详解——了解【父子进程及其特性】(代码演示,画图帮助理解,思维导图,精简)(11)_linux fork-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2161681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入探索卷积神经网络(CNN)

深入探索卷积神经网络&#xff08;CNN&#xff09; 前言图像的数字表示灰度图像RGB图像 卷积神经网络&#xff08;CNN&#xff09;的架构基本组件卷积操作填充&#xff08;Padding&#xff09;步幅&#xff08;Strides&#xff09; 多通道图像的卷积池化层全连接层 CNN与全连接…

应急响应--来不来得及走流程...

免责声明&#xff1a;本文仅做分享&#xff01; 应急响应详解 概述 应急响应是现代信息安全管理中的重要一环。随着网络威胁的日益复杂化&#xff0c;企业和组织必须具备快速响应安全事件的能力&#xff0c;以最大限度地减少数据泄露、业务中断以及经济损失。本文将从应急响应…

华为全联接大会2024 | 一文回顾华为云开发者联盟重磅干货

目录 华为开发者空间预置更多工具资源&#xff0c;带来丰富场景案例 携手鲲鹏、鸿蒙、昇腾等根生态&#xff0c;使能开发者创新 学习体验、内容体系全面升级&#xff0c;助力开发者高效学习根技术 参与丰富线上体验活动&#xff0c;赢取精美礼品 在刚刚结束的华为全联接大会…

香港科技大学广州|金融科技学域博士招生宣讲会——武汉大学、华中科技大学

&#x1f514;&#x1f514;&#x1f514;明日宣讲&#x1f514;&#x1f514;&#x1f514; &#x1f490;香港科技大学广州&#xff5c;金融科技学域博士招生宣讲会 &#x1f4cd;武汉大学专场 &#x1f559;时间&#xff1a;2024年9月24日&#xff08;星期二&#xff09;1…

Vue3:provide-inject实现组件通信

目录 一.作用 1.跨层级通信 2.避免重复声明 3.封装通用服务 二.性质 1.非响应式 2.不可选项 3.高级用法 三.使用 1.爷组件 2.父组件 3.子组件 四.代码 1.爷组件代码 2.父组件代码 3.子组件代码 五.效果 Vue3中的provide-inject机制是用于在组件树中进行依赖注…

python异步处理

python中的异步处理属于比较高级的用法了&#xff0c;用来节省时间非常有用。传统的运行轨迹是阻塞的&#xff0c;就是一行代码必须完成了&#xff0c;然后才能运行下一行代码。异步运行就是我们现在有多个任务task1&#xff08;2s&#xff09;和task2&#xff08;3s&#xff0…

Linux快速安装ClickHouse

ClickHouse官方文档(有中文别忘了勾选) 什么是ClickHouse&#xff1f; | ClickHouse Docs 在线安装 1.安装yum-utils yum-utils是一个与 yum 集成的实用程序集合&#xff0c;可以通过多种方式扩展其本机功能 yum install -y yum-utils 2.增加ClickHouse官方镜像源 yum-c…

某易易盾验证码逆向

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架,本文网址如下,使用base64解码获得: aHR0cHM6Ly9kdW4uMTYzLmNvbS90cmlhbC9qaWdzYXc= ———————————————— 我们来看一下接口请求,这里关注的重点就…

力扣516-最长回文子序列(Java详细题解)

题目链接&#xff1a;力扣516-最长回文子序列 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每…

后端开发工程师转行大模型领域:全面学习路线指南,非常详细收藏我这一篇就够了

随着人工智能技术的迅猛发展&#xff0c;特别是大模型&#xff08;如GPT-3、BERT等&#xff09;在自然语言处理、计算机视觉等多个领域的广泛应用&#xff0c;越来越多的技术人员开始考虑转型至这一充满挑战与机遇的新领域。对于已经在后端开发领域积累了丰富经验的工程师来说&…

如何解决软件企业文件传输难题?这款FTP替代工具一定适合你!

在信息技术飞速发展的今天&#xff0c;软件企业的数据传输需求不断攀升。传统的FTP&#xff08;文件传输协议&#xff09;虽然一度是企业数据交换的中坚力量&#xff0c;但其在多个方面的局限性逐渐成为企业发展的障碍。接下来&#xff0c;我们将探讨FTP的不足&#xff0c;并介…

值得入手的宠物空气净化器——希喂、352、IAM三款产品真实测评

在快节奏的现代生活中&#xff0c;养宠成为很多人的精神寄托&#xff0c;回到家中与猫咪玩耍是一天中最放松的时刻。但这美好的生活也存在着一些烦恼——宠物毛发清理与异味。宠物空气净化器作为一种新兴的清理工具&#xff0c;以其高效、全面的特点&#xff0c;受到了越来越多…

MySQL学习笔记(持续更新中)

1、Mysql概述 1.1 数据库相关概念 三个概念&#xff1a;数据库、数据库管理系统、SQL 名称全称简称数据库存储数据的仓库&#xff0c;数据是有组织的进行存储DataBase&#xff08;DB&#xff09;数据库管理系统操纵和管理数据库的大型软件DataBase Mangement System&#xf…

什么是动态数据脱敏?

原文地址 https://www.bytebase.com/blog/what-is-dynamic-data-masking/ 动态数据脱敏&#xff08;DDM&#xff09;动态更改返回给应用程序或用户的数据库记录&#xff0c;以此来实时保护敏感数据&#xff0c;且不会更改静态数据。 DDM 与静态数据脱敏&#xff08;SDM&#x…

OpenHarmony(鸿蒙南向)——平台驱动开发【MIPI DSI】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 DSI&#xff08;Display Serial Interface&#x…

身为程序员,转行请慎重:考虑以下几点再决定是否转向大模型领域

在决定从程序员转型到大模型领域之前&#xff0c;有几个关键点需要认真考虑。这些因素将帮助你更全面地评估这一转变是否适合你的职业规划和个人情况。 个人兴趣与激情 自我反思&#xff1a;你对人工智能、深度学习和自然语言处理等领域是否有浓厚的兴趣&#xff1f;兴趣是最好…

【论文解析】基于开源 Matrix 指令集扩展(矢量点积)的高性能 RISC-V 处理器“香山”(nanhu 版本)的 LLM 加速的研究

作者及发刊详情 摘要 正文 主要工作贡献 1&#xff09;针对大模型自定义矢量点积扩展指令&#xff0c;并设计了专用硬件加速大语言模型的运算 2&#xff09;基于香山处理器增加矢量点积计算单元和流水线处理逻辑&#xff0c;开发了包含上述指令的处理器nanhu-vdot 3&…

【环境搭建】MySQL安装部署

Win64安装MySQL Windows的玩法比较少&#xff0c;没有像MAC一样给你提供mysqld-safe等等各种的启动脚本&#xff0c;只有手动启动或者是以服务启动Mysql。 点击下载&#xff1a;MySQL5.5-8.0.7z (密码是11) 1.下载软件 这一步下载好软件就可以了&#xff0c;下载地址&#xff…

鸿蒙OpenHarmony【小型系统基础内核(进程管理任务)】子系统开发

任务 基本概念 从系统的角度看&#xff0c;任务Task是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源&#xff0c;并独立于其它任务运行。 OpenHarmony 内核中使用一个任务表示一个线程。 OpenHarmony 内核中同优先级进程内的任务统一调度、运…

《数据压缩入门》笔记-Part 1

一篇文章显得略长&#xff08;超过1w字&#xff09;&#xff0c;本文对应原书序言、前言、第1-5章。 第6-10章请参考Part 2&#xff0c;第11-15章&#xff0c;请参考Part 3。 序言 几点发现&#xff1a; 数据压缩需要花费时间并可能会导致软件变慢&#xff1b;改变数据的组织…