【问题标题】:is there a simple timed lock algorithm avoiding deadlock on multiple mutexes?是否有一个简单的定时锁定算法避免多个互斥锁死锁?
【发布时间】:2011-02-14 18:44:39
【问题描述】:

C++0x 线程库或 Boost.thread 定义了一个非成员可变参数模板函数,该函数一次锁定所有互斥锁,有助于避免死锁。

template <class L1, class L2, class... L3> 
void lock(L1&, L2&, L3&...);

同样可以应用于非成员可变参数模板函数 try_lock_until,它锁定所有互斥体直到达到给定时间,这有助于避免像 lock(...) 这样的死锁。

template <class Clock, class Duration,
          class L1, class L2, class... L3> 
void try_lock_until(
          const chrono::time_point<Clock,Duration>& abs_time, 
          L1&, L2&, L3&...);

我有一个与 Boost 函数 boost::lock(...) 遵循相同设计的实现。但这很复杂。

因为我可能会遗漏一些明显的东西,所以我想知道:

是否有一种简单的定时锁定算法可以避免在多个互斥体上发生死锁?

如果不存在简单的实现,这是否可以证明向 Boost 提出的建议是合理的?

附:请避免发布复杂的解决方案。


注意事项:

  1. 我不想添加比 std::lock(...) 施加的约束更多的约束。
  2. std::lock(...) 不能完全避免死锁。如果两个线程执行 std::lock(l1,l2) 和另一个 std::lock(l2,l1),它只是避免出现死锁。这足以避免很多死锁情况。

【问题讨论】:

  • 而且,如果唯一的解决方案是复杂的,它就不会是提交给 Boost 的第一段复杂代码。
  • @James 我的实现遵循与 boost::lock 相同的设计,非常复杂。如果我们使用现有接口进行简单实现,则可以将其提供给用户。如果实现本身就很复杂,最好在 Boost 上引入它(如果功能当然被认为是有用的),因为用户不会自己实现它。

标签: c++ boost synchronization timeout c++11


【解决方案1】:

经典(也是最好的)方法是定义互斥锁的锁定顺序,并确保一次持有多个锁定互斥锁的任何代码始终按该顺序锁定其互斥锁。这种方法在这里不够吗?

【讨论】:

  • std::lock(...) 不会强制对互斥体下达任何命令。所以我不想为 try_lock_until(...) 添加这个约束。 std::lock(...) 不能避免死锁。如果两个线程执行 std::lock(l1,l2) 和另一个 std::lock(l2,l1),它只是避免出现死锁。这对于很多死锁情况来说已经足够了。
  • 我的感觉是,如果一个程序有线程 A 执行 std::lock(l1, l2) 和线程 B 执行 std::lock(l2, l1),那么程序是错误的。检测和报告锁定顺序问题可能比尝试处理它更合适。
  • 举个例子。两个账户之间的转账功能锁定两个账户。所以如果线程 A 做 transfer(ac1, ac2) 和线程做 transfer(ac2,ac1),那么在 transfer 中使用 lock(...) 可以避免死锁。
【解决方案2】:

我能想到的最简单的方法是,尽管需要认真考虑正确性,但将所有互斥锁锁定为全局排序。实现将是在创建时为互斥锁提供一个序列号。然后,当您将它们锁定为一组时,您可以按该序列号对其进行排序,然后按该顺序进行锁定。不需要特殊类型的锁,因为这样可以保证全局一致的锁顺序。

【讨论】:

  • std::lock(...) 不会强制对互斥体下达任何命令。所以我不想为 try_lock_until(...) 添加这个约束
  • 我猜“最简单”是用词不当;-) 我建议的顺序不是try_lock_until 的一部分,而是互斥体的一部分(即Lockable),因为常规互斥体标识符不足以进行排序,因为它们被重复使用。所以我的建议并不容易,因为它需要更改互斥锁的实现。因此从这个意义上说,由于架构的变化,它可以被认为足够复杂,需要在 Boost 或 STD 端实现。
  • 全局排序无法扩展。您是否已在应用程序中使用此算法?
  • 我看不出全局排序是如何不起作用的。尤其是因为这正是 Jeremy F. 发布的,现已接受的答案。我只是为您提供特定、高效、模块化且不易出错的人工方式来实现完全相同。不,我没有用过这个。我有点提到;-)我不使用这样的东西,因为我最终不会编写最终需要锁定许多资源的多线程程序,因为它只是简单的糟糕的多线程设计;-)跨度>
猜你喜欢
  • 2011-01-16
  • 1970-01-01
  • 2018-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-26
  • 2021-02-19
  • 1970-01-01
相关资源
最近更新 更多