一丶概念理解
1.操作系统决定是否为每个进程分配资源,什么时候分配,什么时候运行,谓之进程调度,进程为程序的动态运行过程,线程为进程的任务执行单位,一个进程可以有多个线程,多个线程可同时运行,并共享进程内的资源,
在单核CPU中,进程跟线程实体表现重合,即线程提出的核心就是在多核心下的并发运行以提高程序效率。
2. 死锁:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
发生条件:1)临界资源竞争条件 ----------资源性质决定,很难从这个死锁条件入手解决死锁问题
2)占有且申请条件 -----------进程占有资源后,申请别的资源时不释放资源,针对该条件的逻辑有:
1)申请资源固定顺序(从小到大或从大到小,亦或是按类分配(设立资源类别数组),如ABC,不能先申请C再申请A),以此达到多个资源申请时,不会互相干扰冲突,缺点为可能用不上(可能程序逻辑先使用C 再很久后才使用A),这种申请方式可能导致逻辑数组的前驱元素利用率过低
2) 直接破坏该死锁条件,当申请失败时,要释放已经拥有的资源,如哲学家进餐问题。缺点是冲突时多次尝试,并发效率较低,且有时可能不符合逻辑。(该申请策略要求全部申请后运行,则可能也导致资源利用 率低下,如果不是全部申请,那么则可能导致申请使用A后,申请B失败,丢弃A时,丧失了运行状态数据)
3)资源不可抢占条件 ------------操作系统资源分配策略为非抢占式调度,解决方法为改成可抢占方式(优先级抢占,优先级可由多种因素决定,如运行时间,进程等级,资源占用数量,等待时间等多种因素,优先级可静态变动也可动态变动)
4)环路等待条件 -------------抽象概念对应现实实体可理解为,资源实体和请求多方间形成了环路图形,即形成了锁,解决方法有
1)银行家算法,一种资源分配策略,分配前检测系统分配后是否安全
2)操作系统层面:当发现系统死锁时,以栈方式pop出程序,直至系统重新恢复运行,关键为硬件支持和死锁的检测
活锁:活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败。 活锁和的区别在于,处于活锁的实体是在不断的改变状态,所谓的“活”, 而处于死锁的实体表现为等待;活锁有可能自行解开,死锁则不能。
单一实体的活锁:例如从队列中拿出一个任务来执行,如果任务执行失败,那么将任务重新加入队列,继续执行。假设任务总是执行失败,或者某种依赖的条件总是不满足,那么线程一直在繁忙却没有任何结果
协同导致的活锁:生活中的典型例子: 两个人在窄路相遇,同时向一个方向避让,然后又向另一个方向避让,如此反复
对应策略:比如引入一些随机性。例如如果检测到冲突,那么就暂停随机的一定时间进行重试。这回大大减少碰撞的可能性。 典型的例子是以太网的检测机制(通信原理,冲突时随机决定重试时间0-2^k-1 倍数等待时间)。
比如约定重试机制避免再次冲突。 例如自动驾驶的防碰撞系统(假想的例子),可以根据序列号约定检测到相撞风险时,序列号小的飞机朝上飞, 序列号大的飞机朝下飞。
3.进程同步/异步 冲突解决策略:
1.进程同步运行:在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系,典型为生产消费者问题,简单说A和B,B开始运行条件的前提为A完成某种操作,如拓扑排序
2.进程异步运行:所谓异步性是指进程以不可预知的速度向前推进。内存中的每个进程何时执行,何时暂停,以怎样的速度向前推进,每道程序总共需要多少时间才能完成等,都是不可预知的,异步运行的程序具有不可预制性,难以重现,
则多个程序在同一临界区异步运行时,可能有各种未知的情况发生。
3.原子性操作:“原子”为名,参考概念“指化学反应不可再分的基本微粒”,以此意指某种事物不可再分,而原子性操作,指的就是该操作不可被别的操作所中断干扰,多个原子操作间时序上独立串行,以此避免对同一数据操作造成的意料外的结果,
这一点对数据库读写,线程/进程 间对 共享资源/竞争资源 的使用上有重要意义。
二丶相应算法策略
1. 银行家算法:
描述:进程请求资源时,对系统状态进行判断,具体逻辑为,计算当前剩余各类资源数量,与请求数量相减,得出分配后资源数量,如果分配的剩余数量足够程序安全运行,则系统安全
设资源种类为K,进程数量为P,则数组结构如下:
1)Available[K]:Available[i]表示剩余资源i的数量
2)MAX[P][K]:Max[ i ] [ j ]表示程序 i 对资源 j 的最大需求数量
3) Allocation[P][K]: Allocation[ i ][ j ]表示系统已分配给程序 i ,资源k的数量
4)Need[ P ][ k ]: Need[ i ] [ j ]表示进程i需要资源k的数量
5) Request[ i ][ j ]:表示当前进程 i 请求资源 j 的数量
安全序列:依次分配剩余资源,使得程序能依次完成,一个状态可有多种序列
逻辑依据:⒈数据D请求资源前,系统处于安全状态,有程序,ABCD,那么,剩余资源为x,即ABDC中,如A获得资源x,足够使得程序完成运行,其完成后释放的资源递归可以给BCD运行完毕
如果D请求资源y,剩余资源x,则判定x-y=k,对任意ABCD,完全分配资源k,如果能使得任意一个程序完成运行,剩余释放资源仍可递归得出安全序列,则请求通过(简而言之,分配后依旧安全则分配)
⒉使用哈夫曼编码构建二叉树,每次选择节点对应 Need < Available数组的节点进行结合,同层次左边小,右边大,如果形成的二叉树每层有且仅有一个available,且在右方子节点,则存在安全序列,
遍历左侧子节点名称即为安全序列。
实现逻辑 1.安全序列判定算法
判定当前系统是否处于安全状态(是否有安全序列),循环遍历Need [ i ][ x] ,若对于每个need[ i ][x] , 0<=x<k,恒有Need[i][x]<Available[x],则输出 安全序列 i ,并释放资源(加给Available数组内)
递归进行判定,直至Need[i][x]全部释放,则系统处于安全状态,.
2.资源请求算法:
对请求资源要求进行判定处理:检测当前时间点系统请求数组Request[i][j],对 数字i ,j 遍历对比对应的 Need[ i ] [ j ] ,Available[ i ][ j ]
令i =0,循环判断
2.1)若Need[ i ][ j ]<Request[ i ][ j ],则请求非法,拒绝请求,,否则进入步骤2.2
2.2) 若Available[ x ]对于每个x都有 Request[ i ][ x ] < 若Available[ x ],则进入下一步2.3,否则挂起请求,i+1,返回步骤2.1进行判断
2.3)对0<=x<k, 计算 Available[ x ]-Requestt[ i ][ x ] =Left[x],让left数组作为参数,传入安全序列判定算法,若存在安全序列则分配,不存在则拒绝。
3.关于简易的资源请求判定原则
1.如果将资源种类限定为1,则由哈夫曼树构造可知,可以将每个资源种类视为单节点,以此与available节点进行结合构造哈弗曼树,成功则有安全序列
扩展:将资源种类判定为k,则将哈夫曼树节点结合的原则改为选择进程i对应大小为k的数组Need[i],小于available则结合,否则拒绝,构造成功则接受
2.部分请求原则:安全序列的判定,实际上是将其need对应的最大值与availbale进行比较,那么如果其在安全序列第一元素,其部分请求也一定能使得其处于安全序列
由实际实现和逻辑可知,安全序列不一定只有一个,如果知道所有的安全序列组合,若有新的请求k,只需要遍历这些组合,看其首个元素是否为请求k对应的进程,是则接受,否则拒绝
2. CAS(Check_And_Swap或者说Compare_And_Set )算法(待补充):
1.c++11,automic头文件描述参考:https://blog.csdn.net/yockie/article/details/8838686
2.CAS算法实现参考:https://blog.csdn.net/weixin_40825228/article/details/80801596
https://blog.csdn.net/yishizuofei/article/details/78353722