Linux进程——进程的创建(fork的原理)

前言:在上一篇文章中,我们已经会使用getpid/getppid函数来查看pid和ppid,本篇文章会介绍第二种查看进程的方法,以及如何创建子进程!


在这里插入图片描述


本篇主要内容:

  • 查看进程的第二种方法
  • 创建子进程
  • 系统调用函数fork

在这里插入图片描述


在开始前,我先来回顾一下如何获取pid,ppid
在这里插入图片描述

进程要想区分就一定会有唯一的标示符,而pid,ppid初始化后就变为内核中的数据,也就是操作系统里的数据,在我们自己开发时,操作系统不会将内部数据暴露出来,不能直接访问,所以通过系统调用接口直接获取pid,ppid。

目录

  • 1. 查看进程的第二种方法
  • 2. 创建子进程
    • 2.1 系统调用函数fork
    • 2.2 fork的一般写法
    • 2.3 fork的原理
  • 3. 总结


1. 查看进程的第二种方法

在Linux系统中,不只有ps能够查看进程,还存在着一个动态目录proc,该目录存放了所有存在的进程,目录的名称。它会随着进程的改变而随时更新它的内容!

查看所有进程:
指令:ls /proc/

在这里插入图片描述

查看指定pid的进程文件:
指令:ls /proc/进程pid

如果想只查看这个目录我们可以:
指令:ls /proc/进程pid -dl

proc查看进程

当我们结束这个进程时,文件也会从proc中被删除


误删可执行程序时

在看完这个视频后,我们发现当我们在程序运行时,误删了可执行程序,进程不会被终止,但是在proc目录中的exe被标红并注明delete

在自行创建的进程中,我们只需要掌握好两个文件cwdexe

  • cwd代表当前工作目录
  • exe指向可执行程序的位置

默认情况下,进程启动所处的路径,就是当前路径,pwd指令其实就是从cwd中找到当前路径的!

当前工作目录是可以通过系统调用进行修改的:
指令:chdir ( " 路径 " )

我们只需要在代码编写时,加入这条指令我们就能更改当前工作目录


2. 创建子进程

2.1 系统调用函数fork

在Linux中,进程的创建方式有两种:

  • 命令行中直接启动进程
  • 通过代码创建

而在用代码创建进程时,实则是进行了系统调用,这里我们就得在学习一个系统调用函数fork!

函数:fork

让我们来简单用man指令了解fork函数信息
在这里插入图片描述
fork的功能是创建一个子进程
让我们来简单实现以下fork
在这里插入图片描述

在这里插入图片描述
我们发现在fork之后函数printf调用了两次!!!

我们再来看看进程的ppid
在这里插入图片描述
在这里插入图片描述

  • 说明了一个情况:fork之后,会创建子进程,并且子进程会和父进程一起进入后面的函数并且分别执行一次

2.2 fork的一般写法

结合目前: 只有父进程执行fork之前的代码(一定),fork之后,父子进程都要执行后续的代码!

  • 因此我们推断fork函数不仅会帮我们创建子进程而且它还有两个返回值,fork成功的时候,会有两个不同的返回值,给子进程返回0,给父进程返回子进程的pid。

首先我们来思考以下问题:

那么我们为什么要创建子进程?子进程的作用是啥?

  • 我们想让子进程协作父进程完成一些工作,这些工作是单进程解决不了的,因此子进程的创建是为了协助父进程,因此父子进程做的是不一样的事情

我们怎么保证父子进程做的是不一样的事情呢?

  • 我们可以通过判断fork的返回值,判断谁是父,谁是子,然后让他们执行不同的代码片段

让我们来看一下fork的一般写法

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<unistd.h>4 5 int main()6 {7     printf("i am a process, 我的pid: %d\n", getpid());8 9 10     pid_t id = fork();11                                                                               12     if(id < 0) return 1;13 14     else if(id == 0)15     {16         // child17         while(1)18         {19             printf("我是子进程: pid: %d, ppid: %d, ret: %d, 我正在执行下载任务    \n",getpid(),getppid(),id);20             sleep(1);21         }22     }23 24     else25     {26         // parent27         while(1)28         {29             printf("我是父进程: pid: %d, ppid: %d, ret: %d, 我正在执行播放任务    \n",getpid(),getppid(),id);30             sleep(1);31         }32     }33 }

在这里插入图片描述
我们可以看到明明我们的fork只使用了一个变量接收但是出现了两个返回值

2.3 fork的原理

关于fork这个函数的原理,我们依然抛出几个问题

  1. fork干了什么事情?
  2. 为什么fork会有两个返回值?
  3. 为什么fork的两个返回值,会给父进程返回子进程pid,给子进程返回0?
  4. fork之后父子进程谁先运行?
  5. 如何理解同一个变量会有不同的值?

fork干了什么事情?

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

  • 以父进程为模板,为子进程创建PCB
  • 但是你今天创建的子进程,是没有代码和数据的!!!目前和父进程共享代码和数据!!
  • 所以,fork之后,父子进程会执行一样的代码

在这里插入图片描述


为什么fork的两个返回值,会给父进程返回子进程pid,给子进程返回0?

在用进程中,一个父进程可能会有多个子进程,但是子进程永远都只有一个父进程,所以父 :子 只会是 1 :n,为了能够更好的管理这些子进程,就必须返回具有唯一性的pid。但是子进程会很容易找到父进程,所以返回0表示成功即可!!


fork之后父子进程到底谁先运行?

创建完成子进程,只是一个开始,创建完成子进程之后,系统的其他进程,父进程和子进程,接下来要被调度执行的,当父子进程的PCB都被创建并在运行队列中排队的时候,哪一个进程的PCB先被选择调度,那个进程就先运行!!

  • 但是PCB的选择调度是由操作系统自主决定(由各自PCB中的调度信息(时间片,优先级等)+调度器算法共同决定)
  • 所以我们不确定父子进程到底谁先运行

最后为什么fork会有两个返回值?

如果一个函数到达了return,那么他的核心工作是否完成?

  • 答案很显然是的,所以。。。

在这里插入图片描述
最后在fork之后代码共享,所以return也会被共享进入父子进程,并在父子进程中分别执行,所以在fork函数return之前,父子进程就已经分流,因此就会产生两个返回值!


如何理解同一个变量会有不同的值?

同一个函数有两个返回值是因为fork后两个进程都被调度了,但是同一个变量会有不同的值?该如何理解?

首先我们思考一下,如果我们杀掉子进程,父进程还会存在嘛?杀掉父进程呢?

分析父子进程是否独立

由此,我们可以得出结论:进程之间运行的时候,是具有独立性的,杀掉父进程不会影响子进程!反之也是!

  • 进程的独立性,首先是表现在有各自的PCB进行之间不会互相影响,代码本身是只读的,不会影响,数据父子是会修改的!代码共享,数据各个进程都会写时拷贝私有一份!
  • 变量id是父进程定义的变量,保存数据,返回的时候发生写时拷贝,不同
    的进程执行的代码中的变量id获取的值不同,所以id在父进程和子进程中值不同

3. 总结

fork函数的内容远不只有这么一点,但是理解这五个问题能快速帮助我们,简单理解这个函数,了解fork的原理!关于如何创建子进程我们就讲到这里!

谢谢大家支持本篇到这里就结束了
在这里插入图片描述

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

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

相关文章

一文了解双向链表

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、链表分类二、双向链表是什么&#xff1f;三、功能函数实现1.申请一个节点2.初始化3.尾插4.头插5.尾删6.头删7.在指定位置后插入8.删除指定位置数据9.查找10…

带环链表问题

带环链表就是字面意思带环的链表&#xff0c;例如以下这三种情况 练习题 1.给定一个链表&#xff0c;判断链表中是否带环. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;快慢指针&#xff0c;慢指针走一步&#xff0c;快指针走两步&#xff0c;两个指针从链表的起…

nginx的前世今生(二)

书接上回&#xff1a; 上回书说到&#xff0c;nginx的前世今生&#xff0c;这回我们继续说 3.缓冲秘籍&#xff0c;洪流控水 Nginx的缓冲区是其处理数据传输和提高性能的关键设计之一&#xff0c;主要用于暂存和管理进出的数据流&#xff0c;以应对不同组件间速度不匹配的问题…

池化整合多元数据库,zData X 一体机助力证券公司IT基础架构革新

引言 近期&#xff0c;云和恩墨 zData X 多元数据库一体机&#xff08;以下简称 zData X&#xff09;在某证券公司的OA、短信和CRM业务系统中成功上线&#xff0c;标志着其IT基础架构完成从集中式存储向池化高性能分布式存储的转变。zData X 成功整合了该证券公司使用的达梦、O…

Windows php 安装 Memcached扩展、php缺失 Memcached扩展、Class ‘Memcached‘ not found

在Windows系统下如何安装 php Memcached 扩展 下载dll文件 pecl地址&#xff1a;https://pecl.php.net/package/memcached 根据版本进行选择 &#xff1a; 解压下载的文件后得到了这么样的文件结构&#xff1a; 配置 移动dll文件到相应文件位置 重点&#xff1a; libme…

FreeRTOS队列集(1-15)

队列集定义&#xff1a;def 队列集只允许任务间传递消息为同一种数据类型&#xff0c;如果需要在任务间传递不同数据类型的消息时&#xff0c;就可以使用队列集。 用于对多个信号量进行监听&#xff0c;其中不管哪一个消息到来&#xff0c;都可以让任务退出阻塞状态 假设&am…

如何利用MCU自动测量单元提高大坝安全监测效率

大坝作为重要的水利基础设施&#xff0c;其安全性直接关系到人民群众的生命财产安全和社会的稳定发展。因此&#xff0c;对大坝进行实时、准确的安全监测至关重要。近年来&#xff0c;随着微控制器单元(MCU)技术的不断发展&#xff0c;其在大坝安全监测领域的应用也越来越广泛。…

【PCL】教程 supervoxel_clustering执行超体聚类并可视化点云数据及其聚类结果

[done, 417.125 ms : 307200 points] Available dimensions: x y z rgba 源点云milk_cartoon_all_small_clorox.pcd > Loading point cloud... > Extracting supervoxels! Found 423 supervoxels > Getting supervoxel adjacency 这段代码主要是使用PCL&#xff08;Po…

【Linux】创建/扩容swap交换空间swap优化

一、当前交换空间大小 目前交换空间大小为2G 二、创建swap交换空间 #创建大小为2G的交换空间 [roothadoop01 data1]# dd if/dev/zero of/data1/swapfile bs1M count2048 #将文件设置为交换空间 [roothadoop01 data1]# mkswap /data1/swapfile #启用交换空间 [roothadoop01 da…

Java Web 开发 - 掌握拦截器和监听器

目录 深入了解Java Web的拦截器和监听器 拦截器&#xff08;Interceptor&#xff09; 拦截器的使用场景 拦截器实例 思维导图 ​编辑 监听器&#xff08;Listener&#xff09; 监听器的使用场景 监听器类型 监听器实例 思维导图​编辑 总结 深入了解Java Web的拦截器…

在UI界面中播放视频_unity基础开发教程

在UI界面中播放视频_unity基础开发教程 前言操作步骤结语 前言 之前我写过一篇在场景中播放视频的文章&#xff0c;但是在开发中有时候也会在UI的界面中播放视频&#xff0c;这期我们做一下在UI的界面中播放视频。 操作步骤 首先在场景中创建一个Raw Image&#xff0c;UI->…

0418EmpTomCat项目 初次使用ajax实现局部动态离职

0418EmpTomCat项目包-CSDN博客 数据库字段&#xff1a; 员工部门表 分页查询&#xff1b; 多条件查询&#xff1b; 添加新员工&#xff1b; ajax点击离职操作效果&#xff1a;

【CTF Web】BUUCTF BUU CODE REVIEW 1 Writeup(代码审计+PHP弱类型漏洞+MD5的0e绕过+反序列化)

BUU CODE REVIEW 1 1 https://github.com/glzjin/buusec_2019_code_review_1 解法 <?php /*** Created by PhpStorm.* User: jinzhao* Date: 2019/10/6* Time: 8:04 PM*/highlight_file(__FILE__);class BUU {public $correct "";public $input ""…

动态数据结构中的表扩张性:摊还分析、伪代码与C语言实现

动态数据结构中的表扩张性&#xff1a;摊还分析、伪代码与C语言实现 引言表扩张性的概念摊还分析在表扩张性中的应用伪代码示例&#xff1a;TABLE-INSERT操作C语言实现结论 引言 在处理数据结构时&#xff0c;尤其是表&#xff08;或数组&#xff09;&#xff0c;我们经常面临…

Idea报错:无法访问org.springframework.boot.SpringApplication

在开发项目时&#xff0c;常常会遇到这种问题&#xff0c;报错信息如下图所示 版本号与jdk版本号存在对应关系&#xff0c;61.0对应jdk17&#xff0c;52.0对应jdk8 所以是某个依赖的版本太高&#xff0c;降低该依赖的版本即可 具体步骤&#xff1a; ①修改pom.xml中spring b…

【linuxC语言】exec函数族

文章目录 前言一、exec函数族二、示例代码2.1 代码12.2 代码22.3 代码3 总结 前言 在Linux环境下&#xff0c;C语言提供了一组强大的函数族&#xff0c;即exec函数族&#xff0c;用于执行其他程序。这些函数允许程序在运行时加载并执行不同的程序&#xff0c;从而实现了程序之…

使用docker部署nacos2.2.3单节点

docker部署nacos2.2.3 首先nacos要配合mysql进行初始化数据&#xff0c;部署一个mysql5.7版本的。 systemctl stop firewalld && setenforce 0 关闭防火墙和selinuxdocker pull mysql:5.7 && docker pull nacos/nacos-server:v2.2.3 拉取镜像docker …

redis中的集群模式

主从复制、主从同步(解决高并发读的问题) 主从同步原理&#xff1a; 1.全量同步 slave&#xff08;从节点&#xff09;每次请求数据同步会带两个参数&#xff1a;replid和offset。 replid&#xff1a;第一次请求同步时&#xff0c;replid和master的replid不一样&#xff0c;这…

探索AI工具的巅峰:个人体验与深度剖析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

[C++] 类和对象 _ 剖析构造、析构与拷贝

一、构造函数 构造函数是特殊的成员函数&#xff0c;它在创建对象时自动调用。其主要作用是初始化对象的成员变量&#xff08;不是开辟空间&#xff09;。构造函数的名字必须与类名相同&#xff0c;且没有返回类型&#xff08;即使是void也不行&#xff09;。 在C中&#xff0…