进程概念相关笔记

一、进程

讨论的是单核cpu
进程的起因:
提高资源的利用率,解决资源的共享性

0、进程的属性:
动态性,共享性,独立性,制约性,并发性
1、 进程的模型:
一个进程就是一个程序运行的实例,进程是有状态的包括,程序计数器、寄存器、变量和当前值,每当cpu 来回切换进程时,需要保存这些数据,当再次被运行时会被再次载入所谓多进程在单核的cpu 上其实也只是伪并行,因为只是cpu按时间片来回切换执行这些进程,人感觉不到而已(内部其实是一个数据结构)。进程是一系列活动,包括程序,输入,输出以及状态
在这里插入图片描述

一个进程的状态就存在PCB中的数据结构
2、进程的创建:

2.1、何时创建:

  • 系统启动
  • 一个进程执行了创建进程的系统调用
  • 用户请求创建一个进程
  • 有一个忽略 哈哈

2.2、父子进程的关系:
父进程创建子进程后,子进程时得到父进程的副本(包括存储映射,打开文件等)。虽然是不同的地址空间但是,指向的是同一个处内存,并且为只读状态,当子进程或者父进程需要修改会对地址进行复制在修改(cow 写时复制技术)

3、进程的终止:

3.1、何时终止:

  • 正常退出:自杀,运行完成后自动退出
  • 出错退出:自杀,运行过程中发生错误,程序捕获到自动终止
  • 严重错误:被杀,干了不该干的事,操作系统把它杀了,比如访问不该访问的地址,➗零等的
  • 被杀:被杀,被别的应用程序杀掉,比如用户执行了kill 命令

4、进程的层次结构:
在Unix中是树状结果,一个进程可以有多个子进程,一个进程只能有一个父进程子 Win中没这样的概念,每个进程都是独立的

5、进程的状态:【重点】

5.1、三个状态(还有七个状态

  • 运行:就是正在运行准确的说是在使用cpu的进程
  • 阻塞:也叫挂起,不会占用cpu 主要是因为有io操作或者系统调用
  • 就绪:已经准备好资源了,只不过其他进程在运行

5.2、几个状态转换的原因:

  • 就绪->运行:调度程序起了作用,将之前正在运行的进程撤掉,从就绪队列中取一个出来执行
  • 运行->就绪:调度程序起了作用,运行太久了会被撤销
  • 运行->阻塞:cpu 使用过程中发生了系统系统调用或者io 操作 就会导致阻塞(?)等待结果返回就会再次放入就绪队列中
  • 阻塞->就绪:io或者系统调用返回了,也就被叫醒了,等着待会干活

6、进程的实现:【重点】

每个进程对应一个进程表项(pcb),操作系统有一张大的进程表来维护这些进程表项其实都是数据结构(在linux 中task_struct 有三百对个字段)
6.1、PCB的典型字段(进程控制块):

  • 寄存器
  • 程序计数器
  • 程序状态字
  • 堆栈指针
  • 进程状态
  • 优先级
  • 调度参数
  • 进程ID
  • 父进程
  • 进程组
  • 信号
  • 各种时间…

6.2、IO中断的过程:
多个进程与每个IO.关联一个中断向量当进程切换时保存好对应的数据后,会调到中断向量指向的位置,这些是由硬件完成的工作,并且是通过汇编实现的

基本过程:

  1. 硬件压入堆栈程序计数器
  2. 硬件从中断向量装入新的程序计数器
  3. 汇编语言过程保存寄存器值
  4. 汇编过程设置新的堆栈
  5. c中断服务历程运行
  6. 调度程序决定下一个将运行的进程
  7. c过程回到汇编
  8. 汇编语言过程开始运行新的当前进程

二、线程

1、 线程的使用(线程的优势):

  • 多个线程可以一个进程实体内的数据
  • 轻量,来回切换线程开销比进程切换小很多
  • 提高程序的效率

2、线程模型
进程当前程序的所有资源,而线程则是CPU调度的实体,线程内共享着进程中的全局变量(会有数据竞争问题),打开的文件夹,子进程,报警以及相关信号,每个线程都有自己的栈空间,同时线程也和进程那样以来回切换的方式运行,造成并行的假象,线层之间是平等的

重点: 每个线程都有自己的栈来存储自己的状态

线程的其他共享内容:
程序计数器
寄存器
堆栈
状态
其他(与进程共享的变量)

问题:子进程的是父进程的复制,那么子进程会共享父进程的线程吗?如果共享在操作文件的时候是否会出现问题

3、POSIX线程:

POSIX是一个标准,提供了一些统一的系统接口,其中包括线程相关的操作接口具体的百度吧

4、用户线程:
可以在不支持多线程的操作系统上实现多线程,操作系统不知道用户线程的存在,进程中有一个线程表用来记录对应的属性,比如程序计数器,堆栈指针等等,通过进程一样来回切换线程也需要不停的保存数据和载入数据
优点:

  • 线程切换不需要进入内核态因此会比系统线程快
  • 没有上下文切换,不需要进入内核态,调度快捷
  • 可以实现自己的调度算法

缺点:

  • 一旦一个进程中有一个线程进入系统调用,那么所有的线程都会被阻塞

5、内核线程:
操作系统支持,有内核来维护所有的线程表,当进程中的一个线程发生阻塞时,操作系统可以让同一个进程中的其他线程运行,或者另一个进程的线程运行,由于创建和撤销线程的开销哦比价答,所有当要撤销一个线程时只是修改一个状态来标识一下。

6、混合线程:

一个系统线程对应着多个用户线程

7、弹出式线程:

更像是一种多线程编程模式,一个请求进来时就会新建一个线程对其进行处理,开销比较大,一般可以通过线程池进行优化

三、进程间通信

如何使用好进程

为什么会需要进程间进行通信

  • 一个进程需要将一个信息发送给另一个进程,比如把处理好的数据发送给另一个进程进行下一步的处理
  • 确保两个进程的处理不会出现交叉(重叠),比如打印机当前进程在打印另一个进程就不允许使用

1、竞争条件:
当两个进程对资源的访问顺序敏感就称为竞态条件,比如一个进程要读取一个内存地址,然后另一个进程却去删除了,就会导致问题,包括文件,其实但凡有共享资源就会出现这样的问题。

2、临界区:

简单的说共享的区域都可以叫做临界区,不过临界区具有以下几个特性
好比公共厕所的一个小房间

  • 只要一个进程能进入临界区(互斥 = 互相排斥 = 有一个进去就必须等到另一个出去后才能进来)
  • 一个进程不能无限期的在临界区内(死锁)
  • 一个进程不会被一个临界区之外的进程阻塞

3、忙等待的互斥:

屏蔽中断: 当一个进程进入到临界区后立即执行屏蔽中断,使其他进程无法进入,问题是不应该把屏蔽中断的权利给用户,虽然屏蔽中断使一个很好的技术
锁变量: 就是有一个变量来控制当前临界区是否有进程在操作,比如将一个变量设置0 进入临界区后将进程设置为1 第二个进程进入之前检查这个变量如果为0就进入,如果为1 就一直等待,这种做法的劣势在于该变量自身就会产生竞条件
严格轮换算法: 有点没太懂,大概就是一直检测一个值直到合适的值才进行某种操作,这种称为忙等待,比较耗cpu但是在能确认进入临界区的时间非常短的话,效率也是很高的,因此在操作系统内核就常用的自旋锁(实现忙等待的一种锁)

Peterson: 也不太懂,总之是不需要的严格轮换的一直忙等互斥的解决方案

TLS 指令: 基于硬件实现,使用一条汇编指令完成其实和锁变量类似,将一个值存寄存器中,当有进程进入后修改值,并将总线锁住,这一系列操作是原子性的(一个指令执行过程中不会发生cpu切换),同样也是忙等需要循环去检测值得变化

4、睡眠与唤醒(同步):

读者和写者的问题,由于其中count变量存在竞态条件所以可能会导致wakeup丢失即试图去唤醒一个为睡眠的消费者

在非忙等的情况下有两种方法解决竞态条件

4.1、信号量(同步):【重点】
和互斥不同的是互斥主要针对共享资源的,而信号量更关注读个进程的协调,信号量大于0则表示资源进程可以进入,等于0时需要,进入睡眠状态,待有进程释放资源时会唤醒一个睡眠的进程
将上述表达改为程序原语后为
P() :表示取走一个资源
V() :放回一个资源并唤醒一个进程

好比餐厅吃饭,里面每进入一个客人就会拿一个号[P()],如果号拿完你就只能现在外边等着[wait()],等里边有一位客人吃完了,那把号放回前台[V()] 然后前台通知[wakeup()]以为正在等待的客人可以进来就餐了

如果是用上面的例子来比喻互斥的话那么就是,没就餐的认可人不停的去问现在可以了没,虽然这样你可以及时的知道有没有空位置,但是前台小姐姐是很烦你的

4.2、互斥量:【重点】

其实就是不需要计数的的信号量,通常用一个二进制位来表示两种状态中一种(lock 和 unlock) 通常基于一条汇编指令实现,当一个线程执行了lock 那么其他进程必须等待该线程执行了unlock。而且必须执行了unlock 才能继续对其进行lock
思考:那么golang中mux 是忙等类型的还是同步类型的?

以上都使用汇编指令

4.3、管程:

4.4、消息传递:
考虑多进程内消息传递与不同主机上的进程消息传递,效率相对于信号量较低

4.5、屏障:

之前介绍的那些都是用于控制单个进程的,而屏障可以控制一组进程,要么阻塞一组进程要么运行一组进程

五、调度算法

5.1为什么需要调度?
在前面有提到多进程的“并行”是通过根据不同的时间片来运行不同的进程来给用户一个同时运行的假象!调度算法的作用就是让cpu 决定下一个时间片运行哪一个进程,以及时间片怎么确定等等!当然选择的过程中需要考虑很多因素总的来说如下

  • 进程的行为:进程的行为分为 IO密集型CPU密集型主要目的是充分利用资源,如果进程是IO类型的,那么就让他尽快的运行让他们忙于磁盘的请求,这时可以多运行cpu密集型的以保证不会限制任务资源
  • 何时调度:主要分为 抢占式非抢占性指定某个进程何时退出如何退出
  • 调度的目标:公平,强制执行,平衡,以及响应时间和吞吐量等性能因素
  • 系统分类:更具系统类型(批处理,交互式,实时)不同,调度算法的侧重点不同

不同系统类型的调度特点

批处理系统:没有临时的突发进程,都是事先安排的好程序所以侧重点在周转时间,吞吐量,cpu 的利用率
交互式:会有突发式的交互式进程,这是需要快速的运行完这个交互式进程(不然用户会觉得卡)
实时系统:对时间准确度高

5.2各种调度算法: 【重点】

忽略一些彩票调度,保证调度之类的算法因为不是重点,只要了解一下就可以了。

5.2.1:先来先服务:
基于一个链表实现的先进先出的队列,这种调度方式最简单,当有任务来时放入队列中,等待它前面的运行完成后最终运行到它,但是问题在于会导致资源不平衡的问题,比如在运行一个cpu密集操作后队列后面有可能全是IO类型再是CPU的操作,此时CPU就会一直闲置

5.2.2:最短作业优先:
第一个先到的进程先运行,后面到达的程序,我们根据他们的运行时间来决定来运行哪一个,这里先运行时间短的优先,因为这样可以降低后面降低平均等待时间,问题在在于必须事先知道这些进程的运行时间(不太现实)

5.2.3: 最短进程优先(最高响应比):
解决最短作业优先存在的问题,即每个进程运行会后会记录其相应的运行时间,根据过往的时间来计算是否先运行

5.2.4:轮转调度:
同先来先服务一样维护一个队列,但是会有规定每个进程运行多长时间,时间片用完后,将进程放入队列尾部等待下一次的时间片,这个解决了先来先服务一个进程占用太久的问题,但是产生了新的问题就是时间片的长度,短了那么cpu 大部分时间都花在切换上了,长了导致某些进程的响应时间变长

5.2.5:优先级调度:
前面的调度算法都是假设所有进程都是平等,但是实际情况是每个进程都具有优先级,比如正在听歌写代码的你,那么这时音乐播放器的优先级就是更低的了,为了解决这怎么一个问题,优先级调度算法为每个进程都标记了优先级,每个优先级都对应一个就绪队列,进行时间轮转,每次用时间片轮转就先处理优先级高的,都结束后会找下一个优先级的程序,优先级的定义一般来自动态赋予和静态赋予。同样该算法也存在问题,就是如果一直有优先级高的进程进来,那么优先级底的进程永远无法运行(饥饿)。

5.2.6:多级反馈队列:
算是优先级调度的升级版,可以自己动态调节进程的优先级,每当一个进程在一个时间片中没有运行完那么该进程的优先级调低,同时每个队列时间片长度不一样,优先级越低,时间片越长

六、哲学家就餐问题

解决方法是和网络中的载波监听类似,当其他哲学家一起拿餐具的时候就对各个哲学家设置一个随机等待时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值