【问题标题】:Recursive lock() call in g++g ++中的递归锁()调用
【发布时间】:2026-01-19 21:20:03
【问题描述】:

为什么下面的代码会导致g++ 5.4.0出现死锁?

#include <mutex>

int main()
{
    std::mutex m;
    m.lock();
    m.lock();
}

据我所知,根据标准,这段代码应该会导致异常:

30.4.1.2 互斥类型 [thread.mutex.requirements.mutex]

6 表达式 m.lock() 应具有良好的格式并具有以下内容 语义:

[...]

12 抛出:需要异常时的 system_error (30.2.2)。

13 错误条件:

(13.1) — operation_not_permitted — 如果线程没有 执行操作的权限。

(13.2) — resource_deadlock_would_occur — 如果实现检测到 会发生死锁。

(13.3) — device_or_resource_busy — 如果互斥锁已被锁定并且 无法阻止

那怎么了?是图书馆的bug吗?

【问题讨论】:

  • 当你使用std::lock_guard 做同样的事情时会发生什么?可能是lock 有一些未指定的细节,例如检测同一线程上的递归。
  • @Joachim Pileborg 已编辑
  • requires 子句指定调用函数的前提条件(7.5.1.4(3.1))。如果不满足,你有 UB (7.6.4.11)。

标签: c++ multithreading c++11 gcc c++14


【解决方案1】:

您的代码具有未定义的行为,因为您违反了先决条件 ([thread.mutex.requirements.mutex]):

表达式m.lock() 应具有良好的格式并具有以下语义:

要求:如果 m 的类型为 std::mutex [...],则调用线程不拥有互斥锁。

【讨论】:

  • 为什么会出现“device_or_resource_busy”错误情况呢?
  • @FrozenHeart 那是另一个线程试图锁定互斥体,但无法被阻止的时候。
  • 我认为如果满足其中一个错误条件,lock() 应该抛出异常。我错了吗?
  • @FrozenHeart:是的。
  • @FrozenHeart [structure.requirements]需求描述了 C++ 程序应满足的约束跨度>
【解决方案2】:

Library Issue #2309 已从 std::mutex 中删除了该异常,因此 g++ 5.4 可能是最新的。

【讨论】:

  • 所以我猜对了,如果lock() 将同一个互斥锁锁定在同一个线程中,它应该抛出异常吗?因为其他人提出了其他理由