首页 > 系统相关 >【Linux】进程3——PID/PPID,父进程,子进程

【Linux】进程3——PID/PPID,父进程,子进程

时间:2024-06-08 19:02:39浏览次数:11  
标签:fork 创建 代码 PID 进程 PPID 我们

在讲父子进程之前,我们接着上面那篇继续讲

1.查看进程

mycode.c

makefile

我们在zs_108直接编译mycode.c,直接运行,然后我们转换另一个账号来查看这个进程

我们可以通过ps指令来查看进程 

 我们就会好奇了,第二行是什么?我们查的是第一行的啊

那个是指令的ps的进程

PID有什么用呢?

一个PID只对应一个进程

这个非常有用,比如说我们可以让一个进程强制停止下来

我们执行下面这个就能让这个进程停止

 程序就被强制停止了

2.通过系统调用获取进程标示符 

2.1.PID——子进程

 我们怎么获得自己的PID呢?

用系统调用——getpid函数

我们用man查一下

我们来使用一下就知道了

mycode.c

makefile 

在执行之前我们先执行这个

注意test是我的可执行程序的名字 

 我们再运行我们编译好的可执行程序

发现右边的也开始出现数据了

发现跟我们查的PID是一样的啊

 我们可以多跑几次,发现PID变了,但是两边的PID都是一样的

2.2.PPID——父进程

PPID是通过函数getppid来实现的

我们还是用man手册查询一下

我们去修改代码

我们重复上面PID的步骤

 

我们再执行我们的test

 完全对的上

我们终止一下我们的程序,我们再打开试试看

我们发现我们的PID变化了,但是父进程PPID没变

那么这个PPID是谁啊

bash进程???

我们每次登录时,系统都会为我们创建一个bash进程

3.通过系统调用创建进程-fork初识

我们可以用man查看fork一下

他的作用是创建一个子进程 

它的用法有的奇怪,我来展示一下

我们运行一下这段代码

 

我们再修改一下代码

再执行一下

怎么还打印到命令行里面来了???

 我们再修改一下代码

 

before是一条,after是两条,为什么呢?

这个是因为fork()的原因

按照手册的说法,fork的返回值既大于0又等于0,这可能吗?????

我们来验证一下

 我们编译运行一下

两个死循环在跑???

这个在c语言是基本不可能的,但是这个在操作系统是可以的

 有没有发现children的PPID和parent的PID是一样的,所以他们是纯正的父子关系

在执行fork之前只有一个进程,执行到fork后就创建子进程,父进程就是原来的那个进程

 创建进程的方式

  1. ./可执行程序
  2. fork()函数

 接下来我们好好来好好研究一下fork函数

程序开始时按照从上往下的执行顺序创建一个执行流,执行到fork时创建子进程,子进程的返回值等于0,父进程的返回值大于0 ,就变成了两个执行流,父进程是旧的那个执行流,子进程是新创建的进程

3.1 为什么要创建子进程?

 父进程创建子进程通常是希望子进程来协助父进程来完成一些工作,这些工作是单进程无法实现的。

 例如:用户在下载某一款软件时,同时存在播放该款软件的官方宣传视频的需求。这就需要子进程来协助父进程来达到边下载边播放的目的。即通过一定手段(通常时fork()的返回值),让父子进程分别执行不同的代码!

3.2 fork()究竟干了些什么?

  1. fork()创建进程后,OS中会多一个进程(子进程)。
  2. 在创建过程中,Linux操作系统会为子进程创建对应的PCB,并用父进程的大部分属性来初始化子进程的相关属性(如子进程的pid、ppid、所在路径等属性信息则是单独实现)。
  3. 最后将该进程链入到运行队列中,等待CPU的调度!!

 而进程 = 代码 + 内核数据结构和数据,并且进程间时是相互独立的。而进程中的代码和数据等是操作系统在创建该进程时,从磁盘上加载拷贝到内存中的。

但创建的子进程是直接在内存中创建的,子进程并没有相应的代码和数据,那要怎么解决这个问题呢?

  1. 实际上,代码只是用于读取的。
  2. 所以Linux中fork()创建的子进程和父进程共用同一段代码。
  3. 但对于数据来说,父/子进程间必然会存在差异(比如pid、ppid等)。
  4. 同时为了保证父/子进程间的独立性,必须在父/子进程中各自独立私有一份。
  5. 而在Linux中采用了写时拷贝的方式来解决这个问题。

下一个问题就是为啥我们在前面的展示中,fork()创建出的子进程只执行fork()后的代码?在fork()前的代码子进程能否“看见”呢?

  1. 答案是子进程能看见fork()前的所有代码!
  2. 至于为啥子进程只执行fork()后的代码,这是由于代码运行过程中,存在诸如epi、pc等寄存器。
  3. 这些寄存器中会保存当前指令要执行的下一条指令的地址。
  4. 而fork()创建子进程过程中,父进程中pc、epi等寄存器的结果也“继承”给了子进程。
  5. 所以才出现子进程只运行执行fork()函数后的代码!

3.3 fork为什么会存在两个返回值?

 fork()是一个函数,其存在返回值。fork()在执行是,操作系统内核做了如下工作:分配新的内存块和数据结构给子进程、将父进程的部分内核数据结构拷贝给子进程、添加子进程到系统进程列表中,调度器开始调度。

 fork()函数执行完后,已经完成了创建子进程、将子进程添加到调度队列中等工作。

当父进程和子进程在调度队列中被调度时,两个进程都需要执行return语句,都需要返回一个值!所以fork存在两个返回值!(操作系统通过寄存器来实现返回值返回两次)(真正原因其实在于地址空间的实现)

3.4 为何fork函数中父进程返回子进程的pid、子进程返回0?

 对于一个进程,其父进程是唯一确定的,但其子进程可能存在多个。就像我们生活中,一个孩子的爹是唯一确定的;但对于一个父亲,其可能存在多个孩子。
 而父进程和子进程之间是管理和被管理的关系。父进程为了更好的管理好子进程,所以fork函数在创建子进程后返回子进程pid;对于子进程来说,其只需管理好自身即可,所以返回0。

3.5 父进程和子进程谁先运行?

 我们已经看到了fork()函数会创建一个子进程。创建完子进程后,子进程会被加载链接到系统进程列表中等待CPU调度运行。
 至于父进程和子进程谁先被CPU调度是不确定的。进程被调度的先后顺序由各自的PCB中的调度信息(时间片 + 优先级等)+ 调度器算法确定。换句话说,父进程和子进程谁先运行是由操作系统决定的!

3.6 为何同一个变量接收两个返回值

 我们前面已经提到过了进程是相互独立的,为例保存fork()创建出的子进程和父进程之间的独立性,我们所采用的解决办法是:父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。具体见下图:

我们来深入了解一下

  • 操作系统在创建子进程时,会先将父进程页表中的访问权限大部分改为只读权限。
  • 然后以父进程为模板,将数据拷贝给子进程。
  • 当子进程或父进程对数据试图修改数据,由于页表中的访问权限为只读。此时该行为会被操作系统识别到。并分为以下两种情况:
  1. 如果代码和数据所处区域本身就是只读的(如:代码区、字符常量区),此时OS认为该行为非法被拦截。
  2. 原本数据可读可写,但操作系统将对应页表中的访问权限设置为只读。当操作系统识别到该信息时,操作系统并不会将行为视为错误,而是作为重新申请内存拷贝内容的一种策略机制。此时操作系统会重新申请开辟空间,拷贝和修改数据,并修改页表中的映射关系。

 3.7.fork创建子进程失败原因

在Linux中,fork()创建子进程失败通常由有以下两种原因:

  1. 系统中有太多的进程。操作系统内存不足。
  2. 实际上,用户使用fork()创建子进程是有次数限制的。当超过该范围时,fork创建子进程失败!

3.8.bash如何创建子进程?

我们看看程序最开始的那个printf,PPID是45106,那么45106是谁呢?

很明显了,就是我们自己的PID

这个bash创建子进程的过程肯定也调用了fork()

标签:fork,创建,代码,PID,进程,PPID,我们
From: https://blog.csdn.net/2301_80224556/article/details/139543666

相关文章

  • 【Linux】进程4——进程状态
    1.进程状态什么是状态?每个人都有状态——颓废,阳光,积极向上。。。。进程也有状态在操作系统中,由于进程的数量是非常多的,而系统的资源又非常少,所以不可能每一个进程在每时每刻都会处于上处理机运行的状态,所以在系统中应该要为进程维护好相关的状态:运行态,终止态,阻塞态,挂起态,......
  • 蚁群优化算法优化PID---核心期刊论文复现
      针对传统的PID控制器参数多采用试验加试凑的方式由人工进行优化提出了一种新型的基于蚁群算法的PID参数优化策略.蚁群算法是近几年优化领域中新出现的一种仿生进化算法该算法采用分布式并行计算机制.在简要介绍蚁群算法基本思想的基础上推导了蚁群算法PID参数优化方法......
  • oracle进程
    每个oracle进程都有自己的任务,oracle会给进程分配内存(PGA)让进程更好的完成任务。oracle进程可以分为三类:服务器进程,后台进程,从属进程。1服务器进程服务器进程是执行客户端会话指令的进程。负责将客户端的指令发送到oracle服务端执行,然后将服务端的结果返回给客户端。可分为......
  • 计算机语言python发展历史进程
    Python语言之父,荷兰人GuidovanRossum。他于1982年从阿姆斯特丹大学取得了数学和计算机硕士学位。20世纪80年代中期,Python之父GuidovanRossum还在CWI(数学和理论计算机科学领域的研究中心,位于阿姆斯特丹)为ABC语言贡献代码。ABC语言是一个为编程初学者打造的研究项目。A......
  • FPGA数字信号处理之:PID调节算法的实现
    一、定义        PID控制是经典控制理论中控制系统的一种基本调节方式,是具有比例、积分和微分作用的一种线性调节规律,它基于对被控对象的测量值与设定值之间的差异进行调整来实现稳定和精确的控制。        PID控制器由比例单元(P)、积分单元(I)和微分单元(D)组成,......
  • 6/7学习进程
    今天上数据库实验课完成了两次实验实验三数据库完整性、安全性实现一、实验目的:使学生加深对数据库安全性和完整性的理解,并掌握SQLServer中有关用户、角色及操作权限的管理方法,学会创建和使用规则、缺省和触发器以及存储过程。二、实验要求:通过实验对数据进行完整性控......
  • 在Linux中,进程间通信方式有哪些?
    在Linux中,进程间通信(IPC)是允许多个进程或线程交换数据或信号的机制。以下是一些常见的进程间通信方式:1.管道(Pipes)允许一个进程将输出发送到另一个进程的输入。可以是匿名管道或命名管道(FIFOs)。#创建匿名管道mkfifo/tmp/mypipe#使用管道echo"Hello">/tmp/mypipeca......
  • 进程间通信九天学习笔记
    进程间通信九天学习笔记day1:基本进程操作fork()返回pid进程idgetpid()获取当前进程IDsystem()执行系统命令day2:管道匿名管道pipe(intpipefd[2])pipefd[0]读操作pipefd[1]写操作有名管道(FIFO)mkfifo(,0644)open()read()write()day3:信号标准......
  • Linux开发:多进程通过shm_open/mmap共享内存
    Linux编程:多进程间通过shmget共享内存_检测共享内存中是否有数据-CSDN博客介绍了通过SYSV的方式进行多进程间共享内存,这种方式属于比较久远的方式。POSIX也提供了共享内存的方法,使用起来要更容易些式其原理是利用Linux的tmpfs(Linux开发:tmpfs文件系统-CSDN博客)$df......
  • Linux学习—Linux服务和守护进程
    在Linux系统中,服务和守护进程是保持系统运行的关键组件。服务是运行在后台的程序,通常在系统启动时自动启动,而守护进程是持续运行的程序,用于监听特定的事件或执行定期任务。本文将介绍如何在Linux环境下管理服务和守护进程,并展示一些实用的命令和代码示例。服务和守护进程简......