进程的初步认识

目录

一、硬件方面介绍

1.冯诺依曼体系结构

2.存储分级

二、软件 方面

1.操作系统是一款进行管理的软件,它可以管理硬件也可以管理软件

2.操作系统如何管理?

三、进程 

1.概念

总结

四、linux中对进程的管理 

1.task_ struct内容分类

2.查看进程

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

4.知识补充

5.一些信号

6.通过系统调用创建进程-fork

1.对于fork返回值有两个的解释

2.如何做到一个函数返回两次? 

3.一个变量如何储存两个值?

4.父子进程谁先运行呢?

 bash

7.进程状态 

1.运行

2.阻塞

3.挂起

8.linux下状态 

 R运行状态(running):

S睡眠状态(sleeping):

知识补充 

D磁盘休眠状态(Disk sleep)

T停止状态(stopped):

X死亡状态(dead): 

Z僵死状态(Zombies)

孤儿进程

9.进程内的访问

10.进程优先级

1.优先级是什么?

2.为什么要有优先级

3.linux中的进程优先级

4.用top命令更改已存在进程的nice:

5.优先级的工作原理

如何判断当前运行的那个队列是否为空 


一、硬件方面介绍

1.冯诺依曼体系结构

abcde都是独立的个体,所以各个单元必须要用“线”连接起来,称为总线,为图中红色

1.系统总线   连接运算器和控制器

2.io总线   连接存储器和输入输出设备

一个程序要运行必须先加载到内存,是因为冯诺依曼体系就是这样子规定的

2.存储分级

二、软件 方面

1.操作系统是一款进行管理的软件,它可以管理硬件也可以管理软件

笼统的理解,操作系统包括:
内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(例如函数库,shell程序等等)

                                                                总体纵览图

操作系统存在的意义是通过管理好底层的软硬件资源,为用户提供一个良好的执行环境 

操作系统里面会有各种数据,但是操作系统不相信任何用户

因此为了保护自身数据的安全,也为了能够给用户提供服务,操作系统以接口的方式给用户提供调用的入口,来获取操作系统内部的数据。

这些接口是操作系统提供的,用c语言实现的,自己内部的函数调用---------系统调用(即上图的系统调用接口)

库函数(lib)vs系统调用

库函数和系统调用是上下层,调用与被调用的关系

所有访问操作系统的行为都只能通过系统调用完成,任何库函数只要试图访问操作系统或者硬件(软硬件资源),都需要经过系统调用

2.操作系统如何管理?

先描述后组织

管理者决策者    操作系统     类比校长

执行者               驱动程序             辅导员

被管理者            软硬件资源         学生

我们要管理学生,先得对学生的信息进行描述,例如学院  姓名  班级  专业等等

每个学生都可以转换成一个结构体

我们再将这些结构体进行组织,例如使用双向链表将每一个结构体进行连接

那么我们对学生的管理就转换成对链表的增删查改了

在操作系统中任何管理对象,最终都可以转化成为对某种数据结构的增删查改

三、进程 

1.概念

一个已经加载到内存中的程序,被称为进程,也被称为任务

可以理解成,正在运行的程序,叫做进程

而一个操作系统不仅仅只能运行一个进程,可以同时运行多个进程,因此我们也必须将进程管理起来,如何管理呢?先描述再组织。

进程 = 内核PCB数据结构对象+ 我们自己的代码和数据

                     这个数据结构对象

                     描述这个进程的所有属性值

任何一个程序在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程的结构体对象----PCB  (process ctrl block 进程控制块),PCB就是一个进程属性的集合

这个集合就是一个struct结构体,里面包含例如:进程编号(PID)  进程的状态 优先级等等,根据进程的PCB类型,为该进程创建对应的PCB对象

我们只需要对PCB进行管理就可以管理这个进程,PCB中含有进程的各个属性,因此也顺理成章地会去记录代码和数据的位置,记录下指针。

(操作系统也是软件,所以开机时也会加载到内存中) 

在操作系统之中,对进程进行管理,就变成了对单链表进行增删查改

总结

计算机管理硬件
1. 描述起来,用struct结构体
2. 组织起来,用链表或其他高效的数据结构 

四、linux中对进程的管理 

Linux操作系统下的PCB是: task_struct

所以

在Linux中描述进程的结构体叫做task_struct。
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息

1.task_ struct内容分类


1.标示符: 描述本进程的唯一标示符,用来区别其他进程。
2.状态: 任务状态,退出代码,退出信号等。
3.优先级: 相对于其他进程的优先级。
4.程序计数器: 程序中即将被执行的下一条指令的地址。
5.内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
6.上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
7.I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
8.记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等

9.其它信息

2.查看进程

1.ps ajx(我们通常会搭配grep来使用)

COMMAND系统运行这个进程时是调用什么指令

2. ls  /proc

这个文件夹内的信息实际上是操作系统将内存中的进程进行可视化(因此这个文件夹里面的信息是动态变化的)

这些蓝色的数字就是相应进程的PID 

(同一个程序进行多次运行时,所产生的PID也会不同)

进入目录,里面存储的是该进程的一些属性,我们这里简单看一下cwd和exe

cwd (current work dir)后面的内容指的是:当前的工作目录

例如我们touch  文件名  来创建一个文件,当touch载入内存变成进程的时候会记录它启动时的工作目录,所以创建的文件在没有指定路径的时候,默认就会在当前路径下创建

exe  后的内容指的是:这个进程对应的文件是这个路径下的这个文件,即指针信息可视化

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


进程id(PID)   使用getpid()
父进程id(PPID)使用getppid()

进程的pid也是它的属性,所以pid也在task_struct中存放

ppid在同一个终端下启动一般不会改变,所有子进程的父进程都是bash

4.知识补充

1.在底行模式下,使用!man也可以直接查询手册

2.多条不同指令可以在同一行进行输入,可以使用&&进行分隔,从左到右一次执行

5.一些信号

kill -9  PID 杀死对应pid的进程

6.通过系统调用创建进程-fork

fork可以创建子进程,即系统里多了一个进程,那么这个进程也需要有自己的task_struct和数据以及代码

因为子进程没有自己的代码所以一般而言,fork之后的代码,父子共享

1.对于fork返回值有两个的解释

  我们为什么要创建子进程呢?是因为我们想让父子进程做不同的事情,所以需要让父和子执行不同的代码块,为了实现这个功能,fork就具有了不同的返回值,对父进程返回子进程的pid(因为字进程查询父进程pid成本低,但是父进程无法准确查询子进程),对子进程返回0,如果失败就返回-1,所以我们可以使用if else来对代码进行分流

2.如何做到一个函数返回两次? 

我们可以猜测到fork函数内的大概功能

pid_t fork(void)

{

1.创建子进程pcb

2.填充子进程pcb相应内容

3.让父子进程共享同样的代码

......

此时由于父子进程都有独立的pcb了,他们都可以被cpu调度运行了

return ;

}

我们可以看到,return位于函数的最后,而此时函数的功能已经被实现,因此return的代码也被共享了

3.一个变量如何储存两个值?

首先我们需要知道进程之间是相互独立的

因为数据可能被修改所以我们不能让父子进程共享同一份数据(可以共享代码是因为运行时代码已经不会被修改了,不会影响进程间的独立性)

所以为了解决这个问题,字进程会进行写时拷贝,当子进程修改父进程的数据时,会重新开辟一块空间,因此当return 返回的值被写入父进程的数据时候,父进程的数据直接被修改,而系统会给子进程开辟一块空间用于储存另一个返回值

4.父子进程谁先运行呢?

由调度器决定,是不确定的

调度器会相对公平地调度

 bash

bash,即命令行解释器,它通过fork创建子进程,执行相应的指令,而它本身继续接收我们的指令,这就是fork创建的父子进程的实际应用

7.进程状态 

操作系统学科上的进程状态一般分为,运行,阻塞,挂起 

1.运行

操作系统会将已经准备好运行的进程放入运行队列中,操作系统根据顺序去调度这些进程,处于这个状态的进程就为运行状态:R 

一个进程并不是放上去一直到执行结束的,每一个进程都有一个叫时间片的概念,在一个时间段内所有的进程代码都会被执行,即并发执行

大量地把进程放到cpu上和拿下来的动作被称为进程切换

2.阻塞

操作系统会像管理进程一样管理硬件,每一个硬件属性的结构体中会存在一个等待队列, 如果进程想要读取某个硬件的数据,那么它就会被排在该硬件的等待队列中,这时候进程就处于阻塞状态,一直等待到硬件已经准备好了,然后这个进程就会被排到运行队列中

等待特定设备的进程,我们称该进程处于阻塞态

3.挂起

当操作系统内部的内存不够了,那么在阻塞状态的进程,它的代码和数据就会被换出到磁盘中(swap盘),等到程序准备好运行了,它的代码就又会被换入到内存中,代码和数据被换出状态下的程序就处于挂起状态

8.linux下状态 

static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

 R运行状态(running):

并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。


S睡眠状态(sleeping):

意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
(interruptible sleep))

由于cpu的速度很快,所以一个进程有很大一部分时间是在等待i/o设备就绪,我们查询的时候基本上是处于S状态,但是当我们执行一个空语句,即例如

while(1)

此时程序不进行输入输出,它就一直处于运行状态了

所以S状态可以对应阻塞状态

知识补充 

如果程序处于  例如S+ R+的状态那么说明该程序在前台运行,这时候我们就不能继续在命令行解释器输入指令了,我们可以

./test.exe  &

这样程序就会转为到后台运行,状态后的加号也会消失,这种进程只能使用kill来杀死

D磁盘休眠状态(Disk sleep)

有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

在等待期间这个进程不能被杀死,对应的也是阻塞状态

T停止状态(stopped):

可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可

以通过发送 SIGCONT 信号让进程继续运行。

kill -19 暂停进程,暂停之后进程状态就会变成T

kill -18继续进程  进程继续后会转为后台运行

T状态有自己的应用场景,可能是要等待资源也可能是单纯被其它进程控制了

例如我们使用gdb调试进程时,运行某个程序并且在某个位置打上断点,进程在该代码处停止的状态就处于t状态,(t和T区别不是很大,暂时可以理解为同一种状态)

X死亡状态(dead): 

这个状态只是一个返回状态,你不会在任务列表里看到这个状态

Z僵死状态(Zombies)

是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)
没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态 

如果处于Z状态的程序没有被读取,僵尸进程会一直占用内存,但不会继续运行,会造成内存泄露

孤儿进程

当一个子进程的父进程被终止(在代码中使用exit(0)),但是子进程继续运行,那么子进程的父进程会被更改为1进程,即操作系统 ,因为如果子进程不被托管,在子进程运行结束后就不会被回收了

(如果将父进程直接ctrl+c终止,那么在父进程被回收的一瞬间,子进程在将父进程更改为操作系统后,子进程也会被回收)

9.进程内的访问

某个进程,它的pcb信息可以储存多种用于访问不同数据结构的指针,也就是说一个进程可以被存放在链表中也可以同时被存放在多叉树等等中。

下面我们简单讲一下进程如何相互访问,下是三点前提信息

1.这是一个双链表的结构体,我们现在有一个struct node* 类型的start变量,储存了第一个进程的一个地址

2.这个进程指向的是link

3.link节点内是指向 前后进程的指针

首先我们假设地址0是一个task_struct*类型的一个指针

(task_struct*)0

我们让它指向它的结构体内的link

(task_struct*)0->link

我们再将其取地址,得到的就是link与结构体的地址(即结构体最开始的那个变量的地址)之间的地址差,因为结构体地址为0。

&(task_struct*)0->link

因为我们现在已经有了一个结构体的link的地址,因此我们只需要将它的地址减去上面所算出的地址差,就找到了结构体的地址。(要使用int强转,转换成一个单纯数值的运算,而不是地址间的运算)

(int)start-(int)&(task_struct*)0->link

我们就得到了结构体的地址的数值,将其强转成task_struct*类型,即可访问该进程的其它内容了

(task_struct*)(int)start-(int)&(task_struct*)0->link

10.进程优先级

1.优先级是什么?

优先级是决定某个进程被访问顺序的一项属性。是一个[60,99]之间的一个数值

2.为什么要有优先级

因为资源是有限的,进程是多个的,因此进程之间具有竞争性,操作系统必须保证大家良性竞争,确认优先级

如果进程长时间得不到cpu资源,该代码得不到推进,进程就会面临饥饿问题。

3.linux中的进程优先级

我们使用ps-l指令可以看到

其中

PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值

PRI即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小,进程的优先级别越高
NI就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值,进程nice值会影响到进
程的优先级变化

程序一般的PRI值为80
当我们对程序进行修正,加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
nice其取值范围是-20至19,一共40个级别

我们每次修改进程的优先级,PRI(old)都为80,当nice的值太大或者太小时,nice值会被限制在-20和19。

4.用top命令更改已存在进程的nice:

top
进入top后按“r”–>输入进程PID–>输入nice值 

(只有root才能更改优先级)

nice和renice也可以更改

5.优先级的工作原理

 

在运行队列中会存在两个指针数组,他们指向对应的对应的结构体,其中下标[100,139]对应[60.99] 的PRI的值,根据PRI值,我们将相应的task_struct链接上去,相同PRI值遵循先来后到的原则,类似于哈希表的处理办法

运行队列中有两个相同的数组,这里为了区分我们将其命名为,waiting和running,即当前run和当前wait,当running中的进程依次开始运行时,新进入运行队列的进程会被插入到waiting中,当running中的进程都运行完毕,他们两个的职能就互换,这样能够避免先进入但是PRI较大的进程一直处在队列的末尾得不到运行。

为了实现上述功能,两个数组的指针会不断被run和wait交换,这两个二级指针用于寻找当前run和当前wait的数组

如何判断当前运行的那个队列是否为空 

我们可以创建数组

char bits[5],里面有40个比特位,对应四十级优先级,每个比特位上的1与0表示该优先级所对应的进程队列里面是否有进程,当bits为0时,说明当前run的数组里面指向的进程都已经被运行完毕。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言 -- 深入理解指针(一)

C语言 -- 深入理解指针(一) 1.内存和地址1.1 内存1.2 究竟该如何理解编址 2. 指针变量和地址2.1 取地址操作符(&)​2.2 指针变量和解引用操作符(*)​​2.2.1 指针变量2.2.2 如何拆解指针类型2.2.3 解引…

Vue2和Vue3的区别Vue3的组合式API

一、Vue2和Vue3的区别 1、创建方式的不同: (1)、vue2:是一个构造函数,通过该构造函数创建一个Vue实例 new Vue({})(2)、Vue3:是一个对象。并通过该对象的createApp()方法,创建一个vue实例。 Vue…

【React】React18 Hooks之useState

目录 useState案例1(直接修改状态)案例2(函数式更新)案例3(受控表单绑定)注意事项1:set函数不会改变正在运行的代码的状态注意事项2:set函数自动批量处理注意事项3:在下次…

C++ 多态篇

文章目录 1. 多态的概念和实现1.1 概念1.2 实现1.2.1 协变1.2.2 析构函数1.2.3 子类虚函数不加virtual 2. C11 final和override3.1 final3.2 override 3. 函数重载、重写与隐藏4. 多态的原理5. 抽象类6.单继承和多继承的虚表6.1 单继承6.2 多继承 7. 菱形继承的虚表(了解)7.1 菱…

springboot三层架构详细讲解

目录 springBoot三层架构0.简介1.各层架构1.1 Controller层1.2 Service层1.3 ServiceImpl1.4 Mapper1.5 Entity1.6 Mapper.xml 2.各层之间的联系2.1 Controller 与 Service2.2 Service 与 ServiceImpl2.3 Service 与 Mapper2.4 Mapper 与 Mapper.xml2.5 Service 与 Entity2.6 C…

论文阅读--Simple Baselines for Image Restoration

这篇文章是 2022 ECCV 的一篇文章,是旷视科技的一篇文章,针对图像恢复任务各种网络结构进行了梳理,最后总结出一种非常简单却高效的网络结构,这个网络结构甚至不需要非线性激活函数。 文章一开始就提到,虽然在图像复原…

【MYSQL】事务隔离级别以及InnerDB底层实现

事务隔离级别 读未提交(Read Uncommitted) 允许事务读取其他事务未提交的数据,可能会导致脏读。 读已提交(Read Committed) 一个事务只能看见已经提交的事务所做的更改,可以避免脏读,但可能…

【C++:默认成员函数初始化列表】

构造函数 特点 没有返回值支持函数重载对象实例化时,编译器自动调用作用不是构造,而是初始化函数名与类名相同无参函数和全缺省的函数,不用传参就能调用的函数叫做默认构造函数 构造函数是一个特殊的成员函数 注:无参构造函数在实…

星辰宇宙动态页面vue版,超好看的前端页面。附源码与应用教程(若依)

本代码的html版本,来源自“山羊の前端小窝”作者,我对此进行了vue版本转换以及相关应用。特此与大家一起分享~ 1、直接上效果图: 带文字版:文字呼吸式缩放。 纯净版: 默认展示效果: 缩放与旋转后&#xf…

简单的手动实现spring中的自动装配案例

简简单单的实现一个spring中的自动装配和容器管理的小骚操作。 1,创建AutoSetBean.java 使用injectBeans静态方法,可以扫描指定包下的所有带MyInject注解的字段,如果在beans的Map中存在这个字段的实例化类,则执行装配。 import…

【UE5.1 角色练习】13-枪械射击——拿出与收起武器

目录 效果 步骤 一、安装射击武器 二、拿武器和收武器 效果 步骤 一、安装射击武器 1. 在虚幻商城中将“FPS Weapon Bundle”添加到工程中,由于我们使用的是5.1版本,我们可以先将该资产放入UE4工程中,然后迁移到5.1版本的工程 2. 打开角…

alphazero学习

AlphaGoZero是AlphaGo算法的升级版本。不需要像训练AlphaGo那样,不需要用人类棋局这些先验知识训练,用MCTS自我博弈产生实时动态产生训练样本。用MCTS来创建训练集,然后训练nnet建模的策略网络和价值网络。就是用MCTSPlayer产生的数据来训练和…

Spring与Quartz整合

Quartz框架是一个轻量级的任务调度框架,它提供了许多内置的功能,包括:支持作业的调度、集群调度、持久化、任务持久化、任务依赖、优先级、并发控制、失败重试等。同时也支持自定义作业类型和触发器类型。与Spring整合步骤如下: …

深入解析.[datastore@cyberfear.com].mkp勒索病毒:威胁与防范

引言 在数字化时代,网络安全问题日益严峻,其中勒索病毒(Ransomware)作为一种极具破坏性的恶意软件,严重威胁着个人用户和企业机构的数据安全。.[ datastorecyberfear.com].mkp勒索病毒便是这一领域中的一颗“毒瘤”&am…

2.5 C#视觉程序开发实例1----IO_Manager实现脉冲输出控制

2.5 C#视觉程序开发实例1----IO_Manager实现脉冲输出控制 1 目标效果视频 目标效果展示 IO_Manager 2 信号输出流程说明 为了防止线程不同步导致输出信号没有被输出, 尽量使用一个输出队列来进行输出的管理 3 IO_Manager中添加内容 3.0 添加两个类 1 Out_Sta…

【课程总结】Day13(下):人脸识别和MTCNN模型

前言 在上一章课程【课程总结】Day13(上):使用YOLO进行目标检测,我们了解到目标检测有两种策略,一种是以YOLO为代表的策略:特征提取→切片→分类回归;另外一种是以MTCNN为代表的策略:先图像切片→特征提取→分类和回归。因此,本章内容将深入了解MTCNN模型,包括:MTC…

Windows 11文件资源管理器选项卡的4个高级用法,肯定有你喜欢的

作为一个每天使用文件资源管理器来管理我的工作流程的人,选项卡帮助我为处于不同完成阶段的工作创建了不同的文件夹。以下是我使用选项卡提高工作效率的最佳技巧。 打开和关闭选项卡 假设你的计算机上安装了Windows 11的最新更新,请按Ctrl+E打开文件资源管理器。在我发现“…

STM32智能家居掌上屏实战:从WiFi连接到MQTT通信,打造你的家庭物联网网关

摘要: 本文深入探讨一种基于STM32的智能家居掌上屏设计方案,详细阐述其硬件架构、软件设计以及通信协议等关键技术细节。该方案利用WiFi构建局域网,实现与各类传感器、执行器的便捷交互,并通过TFT彩屏提供直观的控制和数据展示,旨…

五、保存数据到Excel、sqlite(爬虫及数据可视化)

五、保存数据到Excel、sqlite(爬虫及数据可视化) 1,保存数据到excel1.1 保存九九乘法表到excel(1)代码testXwlt.py(2)excel保存结果 1.2 爬取电影详情并保存到excel(1)代…

大模型周报|15 篇必读的大模型论文

大家好,今日必读的大模型论文来啦! 1.谷歌推出风格感知拖放新方法 Magic Insert 来自谷歌的研究团队提出了 Magic Insert,用于以物理上可信的方式将用户提供的图像中的对象拖放到不同风格的目标图像中,同时与目标图像的风格相匹…