线程同步----睡觉与唤醒

从上一篇文章《 线程同步----锁 》中我们了解了解决线程同步中最基本的一些问题,那就是如何用 锁 来保护合作线程们的临界区数据不被重复修改。但是从这里引出了一个问题,那就是如果一个线程A先进入了临界区且上了锁,等到B线程也到了临界区前发现锁是锁的,那么B只能等待直到A线程执行完临界区代码才能继续往下执行,这样就会导致cpu被浪费的占用,因为B没有做任何事情,只是等待。
 因此为了提高系统的cpu利用率。有了睡觉和唤醒这两种操作,当一个线程B需要等待线程A时,将进入睡眠状态。当A做了该做的事情后,将唤醒B 。A如果需要等待B做一些操作的话,也可以进行睡觉,到时候再被B唤醒。

  简单举个例子吧。假如依旧是x,我需要它始终处于一个范围,那就是0-10之间。
 A线程负责给x++,只要x不到10的时候就必须给x加1 。如果x为10了,自己就去睡觉。.
 B线程负责给x--,只要x不为0,B就一直让x-1。如果x为0,自己就去睡觉。

伪代码
int x=5;
A: 
   while(1)
    if(x==10)                
                                 //flag2
         sleep();
   
          x++;
                                  //flag1
    if(x==1)             //如果x为1则代表x++之前x是0,可能是B-1后导致的,B就可能会睡觉。
        wake(B);

}

B:
  while(1)
{
   if(x==0)
    sleep();
    x--;
   if(x==9)        //如果x为9则代表x--之前x是10,可能是A+1后导致的,A就可能会睡觉。
     wake(A);

但以上的睡眠和唤醒会导致几个问题。
1.使用x时都没有给它加锁,这就会导致线程切换的时候出现对x的误, flag1的位置如果x++后为2,那是不是意味着不满足下面if(x==1)的条件,不用唤醒B,可是 flag1处发生了线程切换,B线程让x--了,x变为1了,此时再又切换回了A线程,A线程是不是就会执行它本不应该执行的wake(B),然而B现在并没有在睡眠wake(B)这局话不起任何作用。这个倒不会导致什么严重后果,出现这个因为没有给x加锁导致的,但是开头也说了,使用睡眠和唤醒这种方式就是为了改正上锁后等待的线程占用cpu的问题,再加锁岂不是本末倒置了。其实也未必,相比与给A,B线程全局加锁来说,只对一些影响结果的操作上锁等待的时间非常短,可以忽略不计。我们可以在x++前和wake后 加入锁优化这个问题。

2.出现了死锁,导致A,B线程都睡死了,没人叫了。 flag2的位置,A线程判断x已经为10了,要去睡觉了,可睡之前切换到了B, B让x--变为9,判断x==9正确,B想着该叫A起来了,可是A现在本来就清醒着。B这一wake(A)就没有用,然后切换回A,A执行了sleep就睡过去了,然后之后就是B一直让x--,直到x为0,自己也睡去了,再也没有条件可以时B去叫醒A了,然后这俩货一直睡,程序死了。
出现这个问题的原因是什么。是不是因为B发的WAKE(A)这个信号在不该执行的时候执行了,因此失去作用了。
这种问题我们可以加锁吗?显然不能的。 问题1为什么可以加锁,因为wake一下就结束了,不会持续,会立刻释放锁;但是问题2这种死锁问题,给A上了锁,A如果执行sleep要一直睡,永远释放不了锁,B线程还怎么愉快的玩耍?不照样还是死!
所以为了解决这个问题,又有了信号量这种概念。这个我们下一篇博客再说。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值