【问题标题】:why std::lock() supports deallock avoidence but std::try_lock() does not?为什么 std::lock() 支持避免死锁而 std::try_lock() 不支持?
【发布时间】:2018-05-11 06:12:29
【问题描述】:

我以为std::lock()std::try_lock()的区别只在于try_lock(),如果锁不可用,立即返回false,而std::lock()则进入阻塞状态。

Cpp reference for std::lock

void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );

使用死锁避免算法锁定给定的可锁定对象 lock1, lock2, ..., lockn 以避免死锁。

Cpp reference by try_lock

int try_lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn);

从第一个开始的顺序调用try_lock,尝试锁定每个给定的可锁定对象lock1、lock2、...、lockn。

我有以下两个问题:

  1. 为什么std::lock() 可以避免死锁而std::try_lock 不能?
  2. 为什么在std::lock 中,锁的顺序无关紧要(可能是lock2、lock 3、lock1,...),而在std::try_lock() 中,锁的顺序保持不变(lock1、lock2、lock3... .)

【问题讨论】:

标签: c++ c++11


【解决方案1】:
  1. 为什么 std::lock() 提供死锁避免,而 std::try_lock 没有?

不需要。如果try_lock 未能锁定所有成员,则它会释放所有成员。如果另一个线程拥有部分或全部这些资源,您将无法从try_lock 获得死锁,因为您将立即返回。

来自try_lock

如果对 try_lock 的调用失败,则不再调用 try_lock,对任何锁定的对象调用解锁,并返回锁定失败对象的从 0 开始的索引。


  1. 为什么在 std::lock 中,锁的顺序无关紧要(它可能是 lock2 ,lock 3,lock1,...),而在 std::try_lock() 中,锁的顺序保持不变(lock1,lock2, lock3....)

我怀疑是因为轻松。不需要死锁避免算法,因为您要么锁定所有死锁,要么无法锁定其中一个,在这种情况下您释放所有死锁。出于这个原因,最简单的锁定方法是 try_lock 从第一个开始并在可变参数模板列表中移动。此外,返回值表明它将返回第一个失败锁的索引。为了实现这一点,您必须从左到右进行迭代。

【讨论】:

  • 如果有锁怎么办,std::try_lock() 会返回true,可以说在这种情况下,它支持避免死锁吗?
  • @Alok try_lock 是的。如果另一个线程也使用 try_lock,那么如果它无法获得任何一个锁,它将失败并解锁所有锁。所以你永远不会陷入僵局。
【解决方案2】:

答案很简单。 std::try_lock 不需要死锁避免机制,因为如果某个特定的锁不可用,它会立即返回并解锁所有获得的锁。另一方面,std::lock() 应该只在获得所有锁后才返回并将它们锁定 - 这就是它需要避免死锁的原因。

考虑2个锁A和B的情况。假设线程2拥有锁B,并希望锁定A。同时,线程1想要锁定A和B。在线程调用std::try_lock 1,将会发生的事情是A被成功锁定,尝试锁定B失败,之后A被解锁(并且函数返回false) - 并且线程2成功锁定A。

另一方面,如果 std::lock 不使用死锁避免,而线程 1 调用它,则事件顺序将是:线程 1 锁定 A,线程 1 尝试锁定 B 并在此处停止,线程 2 尝试锁定 A 并在此处停止。而此时,两个线程都无法取得进展,我们陷入了典型的死锁。

【讨论】:

    【解决方案3】:

    第二季度第一:

    因为try_lock 应该返回第一个失败锁的序号,但lock 必须在返回之前锁定所有锁。

    第 1 次第 2 次:

    为了避免死锁,所有锁定线程之间的锁定顺序必须相同。因此,死锁预防涉及以确定性和可重复的方式对输入进行重新排序。如果锁的序号与调用者相关,则无法对输入进行重新排序,也无法使用死锁预防。

    【讨论】:

    • 锁排序只是一种可以使用的算法。 Here is a study that compares the various algorithms.
    • 锁定的顺序最终将与算法的推送顺序无关(不同)。但我可以看到锁定顺序甚至不是确定性的。在我编辑之前还有什么提示吗? PS:谢谢提示;我真的需要它。
    • 在 gcc、llvm 和 VS 中对当前的实现算法做一个调查会很酷。 :-) 当我 4 年前写 Dining Philosophers Rebooted 时,它是:llvm/libc++: Smart & Polite, gcc/libstdc++: Persistent, VS: Persistent。我不知道今天的实现是做什么的(libc++ 除外)。
    • @HowardHinnant 我会的。但是,如果这是您专业的特定领域,我可以很高兴地进行简单的编辑并等待巨人的完整答复。
    • 我无法访问 VS,因此无法进行完整的调查。
    猜你喜欢
    • 1970-01-01
    • 2021-05-24
    • 2017-11-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2014-05-05
    相关资源
    最近更新 更多