对进程的初步认识以及fork()函数的理解

news/2024/10/29 3:28:17/

什么是进程 

进程是什么呢?其实解释的通俗浅显一点就是我们运行到内存的程序。我们知道运行一个磁盘里的程序时,会将该程序先加载(将磁盘的数据拷贝)到内存当中,因此该程序就可以称为一个进程。首先我们以Windows操作系统为例, 可以快捷键查看当前正在运行的进程:Ctrl+shift+Esc

进程PCB 

 其实在程序加载到内存之前操作系统这个软件早早的就已经加载到内存当中,而当你双击运行程序加载到内存的过程都是操作系统帮你完成的,而你的内存当中肯定不止有一个进程,所以此时操作系统就需要对你的进程做管理。而管理进程并不是管理这款运行起来的软件,而是管理该进程的PCB(process control block)进程控制块。而对进程PCB的理解是这样的,想要管理进程肯定需要该进程的各种属性以及实时状态,所以操作系统就将该进程以一个结构体的形式存储好该进程的所有属性,而该结构体就称为进程PCB。每一个进程都有对应的PCB,最终都由操作系统进行管理。而cpu处理进程时,拿到的就是进程对应的PCB。


所以最终我们就可以初步了解:进程=可执行程序( 代码和数据)+内核数据结构(PCB就是其中之一,方便OS对进程管理) 

 Linux下的进程PCB

我们知道每个进程都有对应的PCB,而PCB其实是一个统称,就像Linux下的进程PCB具体就是struct task_struct的一个结构体。其实每个进程的PCB都是通过类似于双链表的形式衔接起来得,所以可以说,每个人进程的PCB还存放着两个指针,分别指向前后两个节点的数据。

进程id

而这个struct task_struct(Linux下的PCB)存放的核心数据有哪些呢?自然少不了每个进程对应的标识符:pid(进程id)以及所属标识符:ppid(父进程id)

对一个进程的pid 查看可以用getpid指令,而对一个进程的父进程查看可以getppid指令。


但是有一点:每次运行同一个进程时,该进程的id都会发生改变,但是父进程id却不变

 其实我们的命令行当中,父进程一般都是命令行解释器:shell(Linux下的bash)

所以当我们在命令行中输入的所有指令,运行的程序时,对应的父进程都是bash。

 


进程查看 

1

对进程的查看可以采用 ps axj 指令,查看当前进程。所以可以进行测试:

倒计时的一个程序:

执行结果: 

 运行结果如上,我们知道可执行程序运行起来就算是一个进程了,所以进行查看该进程时就可以查看到,而一旦运行结束,该进程也就没了。

2

还可以通过ls/proc查看所有进程,proc其实就是根目录结构下的一个动态目录结构,该目录下存放着所有存在的进程,而proc下的各个目录都是以存在的进程id命名的,而这里面的内容就是关于对应进程在内存当中的信息以及属性等数据。

这里其实有一个进程属性需要提一下,cwd(当前工作目录),默认情况下,进程启动所处的路径就是当前路径。可以通过chdir()函数更改当前进程的工作目录

Linux中进程的创建

  1. 命令行中直接启动进程
  2. 通过代码来创建进程

其实启动进程的本质就是创建进程,而进程一般是以父进程为模版创建的,进程大部分的属性与父进程相同,只有少部分不同于父进程。

初识fork()

通过代码来创建子进程,就要使用到fork函数,这是一个系统调用。

所以在调用fork函数,只有父进程会执行上面的代码,fork之后会以当前进程(父进程)为模版创建子进程,之后系统会执行两个进程,也就是父子进程一起执行。而且该函数会为父进程返回子进程的pid,为子进程返回0。如果fork失败的话就不会创建子进程,则会为父进程返回-1。

测试用例:

执行结果:不断循环

这个执行结果肯定会充满很多疑问???

前言:

执行可执行程序会先将程序加载进内存中,其实在fork函数的内部会以父进程为模版创建子进程,也就是会将父进程的大部分属性都拷贝到子进程的PCB中。然而子进程并不是从磁盘来的,而是在内存创建的,所以父子进程会共享代码,也就是子进程与父子进程指向同一份代码,但是内部的数据却是独立成各自一份(为了防止一方数据修改而影响另一方的执行结果)。进程之间具有独立性,尽管是父子进程,删除一个进程并不会影响另一个进程,并且进程指向的代码是只读的,并不能做任何的修改,不会受到PCB的影响。

但是为什么子进程不会执行fork之前的代码呢??

其实代码是按照顺序依次执行的,执行当前代码时,操作系统内部寄存器(eip)每次都会保存下一次执行的代码数据,所以fork系统调用执行之后会分流,所以eip指向的就是fork之后的代码,而eip这样的程序计数器也会被子进程继承,所以子进程记录的读写位置就是fork之后。

为什么变量i接受了两个返回值??

fork函数内部会为子进程创建PCB,将父进程的核心代码数据都拷贝给子进程,最后返回。但是实际并不是在fork函数完全执行完以后发生分流的,而是在执行完fork的核心代码之后就已经分流了,所以fork的return会被执行两次,分别为父子进程返回相应的值。     

返回实际就是写入数据 ,将数据写入变量i中,而变量i起初是父进程定义的变量,属于数据,而父子进程数据独立私有,避免数据量过大,造成空间浪费,所以满足写时拷贝特性,因此返回的时候发生了写时拷贝 ,导致同一个变量会有不同的值。                            



http://www.ppmy.cn/news/1134493.html

相关文章

C++(List的模拟实现)

1.成员变量 上一节已知信息 list是带哨兵卫的双向链表链表 ,所以list类成员变量应该有 节点以及节点个数信息 private://定义哨兵位Node* _head;//记录插入节点个数size_t _size;2.节点类 每个节点应包含指向下一节点指针、上一节点指针以及自身数据的信息 templa…

柠檬水找零【贪心1】

由于是贪心算法的第一道题,所以先介绍一下贪心算法。 贪心策略:一种解决问题的策略,局部最优->全局最优。(贪婪鼠目寸光) 1、把解决问题的过程分为若干步 2、解决每一步时,都选择当前看起来最优的解法。…

常见开发、测试模型

开发模型瀑布模型螺旋模型增量、迭代敏捷开发模型 测试模型V模型W模型 开发模型 瀑布模型 瀑布模型的每一个阶段都只执行一次,是线性顺序进行的软件开发模式。 优点:每个阶段做什么;产生什么非常清晰; 缺点:风险往…

uni-app:实现元素在屏幕中的居中(绝对定位absolute)

一、实现水平居中 效果 代码 <template><view><view class"center">我需要居中</view></view> </template><style>.center {position: absolute;left:50%;transform: translateX(-50%);border:1px solid black;} </s…

维基百科启用HTTPS的全球影响

2015 年 6 月&#xff0c;维基媒体基金会宣布维基百科默认启用 HTTPS&#xff0c;基金会称此举旨在保护访问者的隐私和安全&#xff0c;让用户能安全和不被审查的自由获取知识。在没有启用 HTTPS 的年代&#xff0c;审查者能知道访问者访问了维基百科上的哪些条目&#xff0c;它…

GROMACS Tutorial 5: Protein-Ligand Complex 中文实战教程

GROMACS Tutorial 5: Protein-Ligand Complex 中文实战教程 前言系统环境特别强调一、预处理阶段1.1 蛋白质配体分离以及除水操作1.2 选择力场识别JZ4配体1.2.1 使用在线力场解析1.2.2 使用官方推荐力场CHARMM36解析 1.3 蛋白的top文件准备1.4 配体的top文件准备1.5 使用CgenFF…

91、Redis - 事务 与 订阅-发布 相关的命令 及 演示

★ 事务相关的命令 Redis事务保证事务内的多条命令会按顺序作为整体执行&#xff0c;其他客户端发出的请求绝不可能被插入到事务处理的中间&#xff0c; 这样可以保证事务内所有命令作为一个隔离操作被执行。 Redis事务同样具有原子性&#xff0c;事务内所有命令要么全部被执…

关于“兆易创新杯”中国研究生电子设计竞赛的一点个人小经验

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、一些基本常识二、赛前准备要充分三、选题很重要&#xff01;&#xff01;&#xff01;四、队友很关键五、一些碎碎念总结 前言 请注意这是我参加“兆易创新…