什么是进程/任务(process/tesk)?
我们电脑中的.exe
文件,如果我们不去双击运行它的话,他只会静静的躺在你的硬盘空间里,也就是说在我们双击它之前,它不会对我们的系统产生任何影响。
操作系统是如何管理进程的呢?
第一步 先描述一个进程(描述一个进程上面的一些相关属性):
操作系统中使用"PCB"(进程控制块)来描述一个进程,在操作系统里面主要使用c/c++来实现相关属性,此处描述就是用C语言中的"结构体",操作系统中描述进程的结构体称为"PCB"
第二步 再组织若干个进程(使用一些数据结构,将描述进程的信息放在一起,以便于增上改查):
使用双向链表将每个进程的PCB来串起来, 这里指的是Linux系统,因为每个操作系统的类型不同,内部的实现也是不同的,至于Windows和iOS是如何实现的我们也不得而知了.
还有一些所谓的进程操作:
创建进程:就是先创建出PCB,然后再将PCB加到双向链表中.
销毁线程:就是找到链表上的PCB,然后将其从链表上删除.
查看任务管理器,实际就是遍历整个链表.
PCB的一些属性:
pid(进程id):
就是进程的身份标识(类比每个人的身份证号)
内存指针:
指明了这个进程要执行的指令/代码在内存的哪里,以及这个进程执行依赖的数据在哪里~~当运行一个.exe,此时操作系统就会把这个.exe加载到内存中,变成进程.
文件描述符表:
程序运行过程中,经常要和文件打交道,进程每次打开一个文件,就会在文件描述符表上多增加一项(这个文件描述符表可以视为一个数组,里面的每个元素又是一个结构体,就对应一个文件的相关信息)一个进程只要一启动,不管你代码中是否打开/操作文件的代码都会默认的打开三个文件~~(系统自动打开的):标准输入(System.in)标准输出(System.out)标准错误(System.err)
这个文件描述符表的下标,就称为文件描述符~
进程调度的基本过程
进程调度的基本过程其实就是,操作系统在考虑如何将cpu资源分配给各个进程
上面的属性是一些基础的属性,下面的属性,主要是为了能够实现进程的调度.
状态:
就绪状态:指的是这个进程随时可以去cpu上执行.
阻塞状态/休眠状态:指的是这个进程暂时不能去cpu上执行.
优先级:
先给谁分配时间,后给谁分配时间,以及谁分的多,谁分的少.
记账信息:
统计了每个进程,都分别被执行了多久,分别都执行了哪些指令。分别都等了多久,目的是给进程调度提供指导依据的。
上下文:
描述上次进程被调度出cpu的时候的执行情况,再下一次进程被重新调度时,可以恢复到上一次的执行状态,并且继续往下执行.
在进程被调度出cpu之前,要把cpu中的寄存器中的数据都保存到内存中(PCB的上下文字段中)
就好比有些游戏的存档
当下次进程再次被调度到cpu上时,就可以从内存中恢复这些数据到寄存器中.
健身安排:
我们可以用每周的健身安排,来加深印象,模拟一下进程调度.
我们健身大概分为4个部分:
A:手臂和肩膀
B:胸部和背部
C:腿
每周有七天,我们每天练一个部分,也可以不练,如果想要进步就要给自己安排合理的训练计划和时间安排.
ps:显然这就是并发,而规划训练时间的过程,就是调度的过程
站在上面的角度我们再来看一下PCB中的进程调度属性
状态
正常情况下,A,B,C三个部分我们都可以连,他们都是就绪状态.
但是如果你某次训练过度导致你的腿/C受伤了,那么就可以认为腿/C现在是阻塞状态/睡眠状态
这样状态的进程就暂时不会进行调度了(暂时不把你的腿部训练排在时间表上).
优先级
比如你的某个部位是你的弱项,那么你就可以多安排这个部位的训练.将其他部位的训练少安排一些.
比如周一.周三.你来训练你的胸部和背部~B
周二训练手臂和肩膀~A
周五来训练你的腿部~C
周六,周天休息,让身体来恢复
记账信息
如果长时间这样安排你的A部分肯定会进步,其他的部分就会相比之下没有那么厉害,那么你就要调整你的训练计划,将其他部位的训练强度加大.
上下文
因为你训练的日程比较近,你可能在某天练的部位不是你计划中当天要练到的部位,就会打乱你的计划,这个时候就需要你对你的训练做好记录,下次你也可以查到之前训练了什么,以及自己该训练那个部位了.
关于线程
为什么要有线程?
线程是啥?为啥要有线程?
因为我们的系统支持多任务了~(上古版本还是单任务)程序猿也就需要“并发编程”
通过多线程,是完全可以实现并发编程的~
但是有个小问题:
如果需要频繁的创建/销毁进程,这个事情的成本还是比较高的。
如果需要频繁的调度进程,这个事情成本也是比较高的
那么如何解决这个问题呢?
主要有两个思路:
1.进程池~(数据库连接池,字符串常量池)
进程池虽然能解决上面的问题,提高效率,同时也存在问题,池子里的闲置进程,不使用的时候也在消耗系统资源,消耗的系统资源太多了~
2.使用线程来实现并发编程~
线程比进程更轻量,每个进程可以执行一个任务,每个线程也能执行一个任务(执行一段代码),也能进行并发编程。
ps:
创建线程的成本比创建进程的成本小得多.
销毁线程的成本比销毁进程的成本小得多.
调度线程的成本比调度进程的成本小得多.
为什么进程重线程轻呢?
进程重在资源申请释放(在仓库中找东西)
线程是包含在进程中的,一个进程中的多个线程,共有同一份资源(内存+文件)
只是创建进程的第一个线程的时候(由于要分配资源),成本是相对高的,后续这个进程中再创建其他线程~这个时候成本都是要更低一些,不必再分配资源了
ps:这里我们还是多理解,可以结合一些生活中的例子,来加深对知识的理解.