zoukankan      html  css  js  c++  java
  • 炸弹问题——一种会引发死锁的情景模式

    有这样一种炸弹,它有一个控制中心,时不时发送消息给它;当它被引爆的时候,它将告诉控制中心, 并把自己从控制中心的联络列表中移除。在通常的代码中,由于接受消息或者引爆的时候,都会引起炸弹的状态变化,所以,我们会使用一个锁来保证这两个操作是有顺序的;另外,控制中心的控制列表也是会有锁来控制访问。下面是其中一个实现:

    https://github.com/AmongOthers/BombsProblem/commits/deadlock_version

    运行过程中将会出现死锁的情况。原因是:

    Bomb:
    public void Fire() { log("Bomb.Fire: lock core begin"); lock (mCoreLock) { log("Bomb.Fire: lock core end"); mCenter.RemoveBomb(this); fire(); } }
    BombCenter:    
       public void RemoveBomb(Bomb bomb) { log("BombCenter removeBomb: lock bombs begin"); lock (mBombsLock) { log("BombCenter removeBomb: lock bombs end"); mBombs.Remove(bomb); } }

    上面的过程需要的锁的顺序是:Bomb.mCoreLock->BombCenter.mBombsLock

    而控制中心呼叫炸弹的过程:

    BombCenter:     
       public void callBombs() { log("BombCenter fireBombs: lock bombs begin"); lock (mBombsLock) { log("BombCenter fireBombs: lock bombs end"); foreach (var bomb in mBombs) { bomb.OnCommandReceived(); } } }
                
      Bomb:
           public void OnCommandReceived() { log("Bomb.onCommandReceived: lock core begin"); lock (mCoreLock) { log("Bomb.onCommandReceived: lock core end"); dumb(); } }

    需要的锁的顺序是: BombCetner.mBombsLock->Bomb.mCoreLock

    当这两个过程并发进行的话,就有可能会造成死锁的情况。本质上来说,这是"哲学家吃饭问题"的变种,但是它比较隐蔽,一般来说,会有一个消息的订阅者的基本模式,而订阅者会自我销毁,并主动要求消息中心从列表中移除自己。这样的套路用的还是蛮多的,但是有可能会产生死锁的问题。

    一种解决方案是,炸弹不直接要求控制中心移除自己,而是设置自己一个“可以被废弃”的标志,而由控制中心在适当的时候移除。

    https://github.com/AmongOthers/BombsProblem/commits/set_remove_flag_version

    BombCenter:
    public void callBombs() { log("BombCenter fireBombs: lock bombs begin"); lock (mBombsLock) { mBombs.RemoveAll((bomb) => { return bomb.IsFired; }); log("BombCenter fireBombs: lock bombs end"); foreach (var bomb in mBombs) { bomb.OnCommandReceived(); } } }

    但是如果账单中心没有所谓的合适的地方放置移除标记了的炸弹(没有自己的线程),那么另外一种解决方案就是,使用"异步移除"。

    https://github.com/AmongOthers/BombsProblem/tree/async_remove

    Bomb:
                public void Fire()
                {
                    log("Bomb.Fire: lock core begin");
                    lock (mCoreLock)
                    {
                        log("Bomb.Fire: lock core end");
                        ThreadPool.QueueUserWorkItem(delegate
                        {
                            mCenter.RemoveBomb(this);
                            fire();
                        });
                    }
                }

    ———————————————————————————————————————————————————————————————————————————————

     炸弹问题的本质是,炸弹的事件引起控制中心的某个数据集合发生变化,而控制中心的线程会遍历集合,对炸弹进行操作。如果控制中心弱化成只是单纯的数据集合,那么就不属于炸弹问题。

  • 相关阅读:
    肥胖儿筛选标准
    文章索引
    面向对象66原则
    [精]Xpath路径表达式
    [精]XPath入门教程
    孕产期高危因素
    “华而不实”的转盘菜单(pie menu)
    xmind用例导excel用例,然后再用python排版
    NSObject
    [self class]与[super class]
  • 原文地址:https://www.cnblogs.com/zhengwenwei/p/2755502.html
Copyright © 2011-2022 走看看