使用信号量Semaphore实现没有饥饿问题的锁

参考LittleBookOfSemaphores中的Morris’s Solution

原理及代码实现

设置锁属性如下
锁属性
我们设置有三个线程waiting空间:room1,room2,room3
waiting空间
其中room3是隐式设置的,里面同一时间只能有一个线程,也可以说是互斥的

初始化锁如下
初始化锁
我们的原理如下

  1. 先将一段时间内发出获取锁请求的线程都放入room1,也就是阻塞在图中代码第48行
  2. 由于信号量s1初始值为1,第一个进入room1的线程可以继续执行48行之后的内容,它可以进入room2,也就是被阻塞在图中代码第67行的位置。
    它在room2中进行了一个操作,就是判断自己之后是否还有线程在room1中被阻塞,若有的话,随机唤醒一个进入room2,若没有了,就通知room2中的线程可以依次进入room3
  3. room1中的线程全部进入room2,最后一个线程发出s2的post,room2中的随机一个线程被唤醒,在图中代码第69行开始继续执行,离开room2(进入room3),执行线程的主体程序,然后释放锁
  4. 释放锁时,线程会回头判断身后room2中是否还有线程被阻塞,若有,随机唤醒一个进入room3,若没有了,就通知这段时间内被阻塞在room1门外也就是图中代码第42行的线程可以依次进入room1

获取锁
获取锁
释放锁
释放锁

通过这一种方式,我们一批一批处理请求获得锁的线程,缓解了有线程从一开始就被阻塞,直到几乎所有线程都执行完才轮到执行的饥饿问题。

效果验证

为了证明确实较好地解决了饥饿问题,我设置一个数组starve,用来存储各个线程的饥饿值。

  1. 当有一个线程执行acquire锁的时候,该线程的饥饿值+1,且所有线程的饥饿值乘2
    饥饿1
  2. 当线程执行release锁的时候,对应饥饿值清0。
    饥饿2
  3. 当我们执行room3中的线程主体部分时,打印所有线程的当前饥饿情况,并累加到一个sum值中,执行全部线程结束后打印总饥饿度sum。同时我们也通过maxx变量记录最大饥饿值。
    饥饿3

执行结果:
饥饿测试1
总饥饿值为77208,最大饥饿度为1024

这样看好像还看不出什么,但是我设置了一个会产生饥饿的锁进行比对
简单的单信号量存在饥饿问题的互斥锁:
饥饿锁
也是一样的饥饿算法
饥饿测试2
最大饥饿度就达到夸张的1073741824!!

两者相比就能看出优化效果之好了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值