操作系统和进程

操作系统也叫os,平时大家手机上的安卓苹果,电脑上windows,本质上是一类软件,这个软件主要有两个功能,对下要管理好各种硬件设备,硬件有cpu内存硬盘显示器键盘鼠标摄像头麦克风等,这些硬件设备如何相互配合和如何协调的进行工作如何控制硬件完成一定功能全靠操作系统从中调和,对上要给软件提供稳定的运行环境,qq 浏览器各类软件,这些软件都是运行在操作系统之上的,此时就需要让操作系统给软件提供足够稳定的运行环境,换句话说这些软件想要什么运行环境操作系统就给提供什么,这时候完整的计算机才能帮我们解决问题,这是我对操作系统直观的认识

7c7922cf6176437da46557883fa921d9.png

如果某个应用程序想要操作硬件设备,想要从硬盘读一个数据,需要通过操作系统间接完成 

而操作系统本身是一个很大的话题,是一个非常复杂的软件,原不只上面这些,它还要很多模块和功能还有很多逻辑,这里我们只介绍很关键概念,其中有一个和程序员密切相关的功能模块叫进程管理.

首先什么叫进程(process),光看见这个词可能会很抽象它还可以叫任务(task),任务是啥做某个工作的过程就叫任务,再具体来说一个运行起来的程序就是进程

54e015cc3ba946a1907e7b73b97323e5.pngexe大家应该都不陌生,可执行文件也可以把它称为程序,但是如果你不双击它,它只是一个文件在硬盘里面待着,双击就跑起来,操作系统就会执行程序对应的逻辑,于是就在系统中形成一个进程,在任务管理器就可以看到跑起来的进程

85877b352b164fdf9eea9f0ce1b68ab1.png

这些都是系统中正在运行的进程,这些进程都是咋来的都是.exe运行起来的形成一个进程,如果你没有双击exe它只是在硬盘上待着是一个静态的,并没有执行这个程序里面的逻辑,但是当你双击运行就会在我们系统中出现一个进程,操作系统就会读取程序每一条指令开始往后执行,于是就完成了具体的工作,运行qq音乐就可以听歌,运行qq就可以上网聊天,这时候就具体的完成一个又一个任务了这样一个概念我们就成为进程。

进程管理(进程多了才需要管理)

所谓进程管理其实分为两步:

1.描述一个进程:使用结构体/类,把一个进程有哪些信息表示出来.

2.组织这些进程,通过一定的数据结构把这些结构体/类放到一起.

把它们管理起来才方便后续的操作和针对进程的工作去展开详细的过程

上述描述一个进程信息使用结构体是为什么,因为主流操作系统都是用c语言来写的,并没有类这样的概念,java是通过类来描述

pcb(描述进程的结构体)

1.pid(标识进程的id,每一个进程都需要唯一的身份标识)

2.内存指针(我们进程想要跑起来,想要工作一定需要硬件设备的支持)你要干活就需要分配资源,进程要跑起来需要消耗硬件资源比如内存,这里内存指针不是一个属性而是一组值,具体点就是进程使用了哪些内存上资源

3.文件描述符表,文件描述符(标识被打开的文件),而一个进程可能打开多个文件,就会对应一组文件描述符,再用顺序表数据结构把文件描述符放到一起构成文件描述符表,具体概况进程运行使用了哪些硬盘上的资源。

所以进程运行会从操作系统这里申请资源,反过来说进程是操作系统资源分配的基本单位,而这里的资源有内存资源硬盘资源还有cpu资源

4.cpu相关属性(具体来说都是辅助进行进程调度)

这里我们明确一个很重要的概念我们的程序能够跑全靠cpu,每个程序相当于一组二进制指令的集合qq.exe这里面包含很多二进制指令,这些指令都在cpu上运行

cpu它怎么运行呢?这里它有一个基本的概念叫核心数

78f0385e5ea44440879c6f4e00a6b2c2.png

我这个cpu有4个内核8个逻辑处理器(8个核心),4核8线程,cpu里有4个核心,4个核心同时干8个人的事,虽然能够同时干8个人的事情,但是在任务管理器里面有这么多进程需要干活

1995017dbe784c1c807bf8b16e902a3a.png0c607a7aa8bd4546a88d0d0727b3fbbf.png

干活的人有8个,需要做的事情有90个(而且必须保证同时干),这就是典型的狼多肉少.

如何解决以上问题,我们聪明的程序员想到了一个解决方案并发,对立的还要并行

并行是两个cpu核心数同时执行两个进程

,并发是一个cpu核心数先执行一会进程1,过了一会再执行进程2,再执行进程3,这样反复循环就是并发,只要切换速度足够快看起来进程1和2和3同时在执行,这里同时并不是真正同时,只是看起来像,就比如即使用qq聊天又使用qq音乐听歌,这两个进程就又可能按照并发执行,虽然只有8个核心,但是通过并发+并行执行也可以达到同时执行这么多进程了,实际上,并行+并发其实是操作系统自行控制的,程序员感知不到,所以我们把并行和并发统称并发,总结下来其实就是很多进程需要同时进行工作,执行是通过并行还是并发都是操作系统随机调度执行的

高并发(一个核心执行1w个进程,当然这个是相对而言,并没有具体的数值)

为了能够实行进程并发就需要进程调度,进程调度就是为进程并发支撑的,来保证cpu核心切换进程足够高效并且有条不紊执行

关于并发举一个简单例子:

假设我是一个妹子(长得好看+有才华),同时只能交往一个男朋友,追我的一共有三个人

1.帅

2.有钱

3.嘴巴甜

但是我有点欲求不满,追我的人并不都是完美的,要么长得帅没钱,有钱长的不帅,即没钱也不帅,为了追求完美,所以我决定同时交往三个男朋友,怎么同时交往三个,这时候就通过并发的方 式来交往(同一时刻不能让对方知道我其他男朋友的存在还有碰面),我可以拍个计划星期135和帅的玩,246和有钱的玩,周天和嘴巴甜的玩,在微观上(同一天角度)我是在和同一个人交往,但是站在一个月(宏观上)我就是在和三个人同时交往,并发并不是同时在执行,只有调度的足够快在宏观看起来就是在并发执行,而很幸的是操作系统调度就是极快的,一次可以调度几百次上万次,作为普通用户是感知不到的.

进程调度需要pcb提供一些属性(通过以下属性进行进程调度)

1.进程状态

阻塞状态和就绪状态

拿上面的例子,有钱的可能出差几周,在这里就发生阻塞,剩下两位随叫随到就是就绪,所以在接下来计划里,给就绪的两位排满约会时间,等有钱的出差回来(变为就绪状态)再继续按照之前的计划执行

2.进程的优先级

进程之间的调度不一定都是公平的,有的是优先调度,拿上面的举例

有钱的最先调度,然后是帅的,最后是嘴巴甜的

3.进程的上下文

就是描述进程执行到哪里的存档记录,在进程离开cpu就需要把当前运行结果进行存档,等下次回来再读档继续往后执行,而具体到进程,所谓的上下文指的是进程运行过程中,cpu内部的一系列寄存器的值,cpu里面也能存数,只不过存的空间很小,cpu存空间的组件叫寄存器,寄存器有很多种,其中最典型的作用是保存当前进程执行的中间结果包括进程运行到哪一条指令,此处我们需要进行调度,需要把寄存器里面的值保存到pcb上下文字段中,下次进程回来cpu,再把pcb中的值值恢复到寄存器,为什么要保存,其实就是cpu核心有自己的一套寄存器,现在进程要离开cpu了,cpu要执行别的进程了,这些寄存器就会被赋予其他含义,就要表示另外进程的执行结果了,如果不把之前的值保存好,那么后续可能就找不到了,所以这里就需要存档和读档的过程

4.进程的记账信息

统计每个进程在cpu上执行了多久,可以作为调度的参考依据

pcb的属性其实是非常多的,以上只是介绍了pcb几个核心的属性,其中进程的调度,并发并行等概念是非常关键的!!!

描述就是通过pcb结构体进行表示进程的属性和信息,那么组织就更简单一些操作系统往往使用双向链表这样的结构来组织pcb

1.创建一个进程就是创建一个链表的节点

2.销毁一个进程就是删除链表的一个节点

3.遍历进程列表就是在遍历链表

比如任务管理器可以看到这么多进程

3e8063c3af8e491e95f5b6ba22056aa7.png

就可以想象操作系统把pcb链表遍历了一遍取出每一个节点,展示在上面

内存管理

操作系统给进程分配的内存是以虚拟地址空间的方式进行分配的,换句话说每个进程访问的内存地址,都不是真是的物理内存的地址,这样一个操作就引入了进程的隔离性

9635ab7978684f7d91eb0ec618f3f238.png

 

上面就是大家电脑里面都有的物理内存(内存条)

1338a9ac8b6a468c851918d1b7e22b67.png

这个图就是物理内存分配给进程的内存资源分别有两个地址0x1和0x2,每个进程都直接访问物理内存地址,此时就会产生一个重要的问题,如果进程1出现代码bug(数组下标越界,空指针异常)可能就会把进程2的内存里内容搞坏,本来进程1只能操控0x1地址的空间,但是一旦出现bug不小心把0x2数据给改了,那就会出现两个进程相互影响,此时进程1bug引起进程2bug这就比较麻烦了,就比如我正在用qq音乐听歌,qq音乐出现bug,就会导致正在运行的浏览器也崩溃了,这对于操作系统稳定性来说是一个很严肃的问题,我们希望操作系统给进程提供稳定的运行环境,很显然当前是不行的,于是我们引入虚拟地址空间来解决这个问题

27eb7fead13f4ba09aa009b92b454cc3.png给两个进程分配两个虚拟内存空间有两个虚拟地址0x11和0x22,站在这俩进程角度来看,两个进程操作的只有虚拟地址这一块,它俩自身是感知不到实际物理内存地址是啥,进程只能看到自己的虚拟地址,然后我们在操作系统提供一个专门数据结构叫做页表,通过页表把内存进行映射,映射到物理内存的区域,0x11通过页表映射到物理内存的0x111地址空间,0x22映射到0x222地址空间,如果进程1再次出现bug此时就没事了,任何一个内存操作都会通过页表来翻译一下,拿着出现bug的地址,发现页表没有,无法翻译,也就无法真正修改物理内存,也就不会对其他进程进行干扰,最大的目的是方便校验,你哪个进程出现bug哪个进程崩溃,这样也就引出了进程的独立性,一个进程无法直接干预另一个进程的内存内容,每个进程都有自己独立的地址空间,大大提升了操作系统的稳定性,虚拟地址空间除了独立性外还要别的优势

进程间通信

但是有时候进程之间需要进行交互,相互配合,如果每个进程可以直接访问物理内存是没有隔离性的,也就不需要进程间通信,直接把算好的结果写到别的进程的物理内存里,这种设定不好会带来不稳定的运行环境,所谓进程间通信是在隔离性的前提下,找一个公共的区域,让两个进程借助这个公共区域进行数据交互,在隔离性的前提下做了一个小小的妥协,不可能做到百分之百隔离,隔离的太严实有些需求和功能完成不了,在隔离的基础之上放开一点小小的口子,这个小口子对我们隔离性大局情况没有影响的前提下完成相互通信和交互

操作系统提供进程通信方式有很多种管道,消息队列,共享内存,信号,他们的本质都是借助公共区域来进行交互,有的公共区域可能是在内存

而在java圈子里并不是很鼓励多进程编程,主要使用文件,socket这两种方式完成进程间通信

多线程

而在java里非常鼓励多线程编程,多进程编程和多线程编程都能满足并发编程(同时处理多个任务)需求场景,多线程编程能够类似起到类似的效果,首先进程的存在目的就可以让操作系统并发的执行很多任务哪怕核心不够也能够完成很多任务,这就靠系统里面的并行并发进程调度来完成

而进程是比较重量的(速度慢/消耗资源多),创建一个进程成本高,销毁一个进程成本高,调度一个进程成本也很高,它虽然也能进行并发编程但是不是一个高效的选择,这里就需要用到线程,都能达到同样的效果,而且更轻量级,成本小

进程为什么这么重量主要体现在资源分配上,资源分配往往是一个耗时操作,创建进程,系统需要找自己空闲内存找出一块合适的进行分配,找的过程就是耗时的,销毁进程归还资源也是消耗时间的,进程之间切换调度也是耗时的,,而系统中有很多进程都在进行申请资源,先来的先申请,后来的需要等待,等待过程的时间也是耗时的

而线程是什么,我们约定,一个进程里可以包含很多线程,每个线程都是独立的执行流,这些执行流本身就是并发执行的,而且他们共用同一份进程申请的内存资源,省下了资源分配的开销,从而降低成本,举一个例子

a6db12c83a674c7aa993355998a558c5.png

工厂就代表一个进程,机器就是线程,但是最近订单量比较大,需要更多机器来完成,所以我有两个方案第一个我再建一个工厂,然后买些机器来完成任务,相当于我现在有两个工厂,但是这样做并不高效,他成本费用比较大,搞一个工厂还需要搞地(再申请资源),完了以后两个工厂也是并发执行干活的之间是独立的互不影响

c18a2644fec241ce85e8a5be8a9f6fe5.png

第二个方案是同一个工厂再买一个机器,这两个机器也是独立生成,这两套机器共用同一个资源,于是成本就大大降低了,所以更加推荐多线程处理

490e625dead740f2aa1a091b6a89c76e.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值