【问题标题】:How to avoid deadlocks?如何避免死锁?
【发布时间】:2009-06-29 07:52:18
【问题描述】:

当使用多线程时,共享内存需要被临界区锁定。但是,使用临界区会导致潜在的死锁。如何避免它们?

【问题讨论】:

  • 为什么投反对票?更重要的是,为什么要关闭它?
  • 制作这个社区 wiki - 现在它看起来就像是声誉农业
  • 嗯。对我来说,这听起来像是一个非常有效的问题,我真的很想看到答案。
  • 将此作为“不是一个真正的问题”结束是愚蠢的。虽然这可能是重复的,但这绝对是一个真实的问题。
  • 投票支持重新开放。这是一个非常重要、非常有趣的问题。

标签: multithreading language-agnostic concurrency


【解决方案1】:

一种方法是使用关键部分的层次结构。如果您确保永远不会在其子级中输入父级临界区,则不会发生死锁。困难在于强制执行这种层次结构。

【讨论】:

    【解决方案2】:

    此页面右侧的相关列表包含一些链接,提供有关该主题的有趣信息。

    除了该列表之外,还有许多其他 SO 问题讨论该主题,例如

    ...and many more

    【讨论】:

    • 谢谢,我会看看这些问题。
    【解决方案3】:

    当我使用 C++ 工作时,以下内容对我有用:

    1. 线程安全类锁的所有公共方法(不包括 ctor 和 dtor)

    2. 私有方法不能调用公共方法

    这不是一般的死锁避免方法。

    【讨论】:

      【解决方案4】:

      您可以改用消息传递(同步和异步调用)来避免临界区。在使用同步调用的时候,你还是要确保不要进行循环调用,在循环调用中线程A问线程B一个问题,而B需要问A一个问题才能响应。

      另一种选择是改为进行异步调用。但是,获取返回值比较困难。

      注意:确实,消息传递系统是使用锁定调用队列的临界区实现的,但它被抽象掉了。

      【讨论】:

        【解决方案5】:

        在进入临界区的各种方法中——信号量和互斥锁是最流行的。

        • 信号量是一种等待机制,互斥量是一种锁定机制,这个概念最容易混淆,但简而言之,激活互斥量的线程只能停用它。考虑到这一点...

        • 不允许任何进程锁定部分资源,如果一个进程需要 5 个资源,则等到所有资源都可用。

        • 如果你在这里使用信号量,你可以解除阻塞/解除等待其他线程占用的资源。我的意思是先发制人是另一个原因。

        我说的这2个是基本情况,常见的4个注意事项中剩下的2个可以和这些有关。

        如果你不同意 ps 添加 cmets。 gtg 已经晚了,后面我会添加更清晰更清晰的解释。

        【讨论】:

          【解决方案6】:

          您必须非常仔细地编写多线程程序。没有捷径可走,您必须了解程序的流程,否则您将注定失败。

          【讨论】:

            【解决方案7】:

            以下算法用于避免死锁:

            银行家算法

            -施加比预防死锁更严格的条件,以试图获得更好的资源利用率

            –安全状态

            •操作系统可以保证当前所有进程都可以在有限的时间内完成它们的工作

            –不安全状态

            •并不意味着系统死锁,而是操作系统不能保证当前所有进程都能在有限时间内完成工作

            ——要求仅当分配导致安全状态时才将资源分配给进程。 – 它有许多弱点(例如需要固定数量的进程和资源),使其无法在实际系统中实现

            【讨论】:

            • 您好,欢迎您。您可以通过更详细地解释您所做的事情来发布更好的答案。你用过算法吗?在什么情况下?为什么在这种情况下推荐它?
            【解决方案8】:

            一种方法是使用非阻塞锁定功能。例如,在 rust 中,您可以使用 std::sync::Mutex::try_lock 而不是 std::sync::Mutex::lock

            所以如果你有这个示例代码:

            fn transfer(tx: &Mutex<i32>, rx: &Mutex<i32>, amount: i32) -> () {
                let mut tx = tx.lock().unwrap();
                let mut rx = rx.lock().unwrap();
            
                *tx -= amount;
                *rx += amount;
            }
            

            你可以这样做:

            fn transfer(tx: &Mutex<i32>, rx: &Mutex<i32>, amount: i32) -> () {
                loop {
                    // Attempt to lock both mutexes
                    let mut tx = tx.try_lock();
                    let mut rx = rx.try_lock();
            
                    // If both locks were successfull,
                    // i.e. if they currently are not
                    // locked by an other thread
                    if let Ok(ref mut tx) = tx {
                        if let Ok(ref mut rx) = rx {
                            // Perform the operations needed on
                            // the values inside the mutexes
                            **tx -= amount;
                            **rx += amount;
            
                            // Exit the loop
                            break;
                        }
                    }
                    // If at least one of the locks were
                    // not successful, restart the loop
                    // and try locking the values again.
            
                    // You may also want to sleep the thread
                    // here for a short period if You think that
                    // the mutexes might be locked for a while.
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2013-06-07
              • 2012-08-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-12-17
              • 1970-01-01
              • 1970-01-01
              • 2011-01-29
              相关资源
              最近更新 更多