为什么解锁一个未解锁的 std::mutex UB?

Why is unlocking an unlocked std::mutex UB?

解锁未锁定的 std::mutex 是 UB。为什么会这样?为什么它不只是没有效果,因为互斥体还没有被锁定,或者已经被解锁,那么再次调用解锁有什么害处?

Unlocking std::mutex that wasn't locked is UB. Why is it so? Why isn't it just have no effect, as mutex isn't locked yet, or was already unlocked, so what's the harm of calling unlock again?

因为那是有代价的。这将要求每个实现都包含必要的内部检查以确保此行为。

如果您想要一个具有这种行为的互斥体,您可以编写一个代码。但是你将不得不为此支付额外支票的费用。但是不需要这种行为的人就不会支付这些费用。

成本往往比您想象的要高。拥有一个互斥锁可以安全地访问受该互斥锁保护的所有内容。如果您不拥有互斥体,则访问受该互斥体保护的内容是不安全的。因此,在某些实现中,这可能需要在释放互斥锁之前获取互斥锁(因此您可以安全地访问互斥锁的所有权数据)。如果获取和释放互斥锁的成本相当,那么解锁互斥锁的成本可能会翻倍。呸

这是历史。
可以从 semaphores 实现互斥锁。在此实现中,Unlocking 递增计数,锁定测试它不为零,然后递减它。 (如果没记错的话,你需要另一个信号量来锁定“测试”位——但对于这个问题我会忽略它)。互斥锁的唯一有效值是 0(锁定)或 1(解锁)。 通过锁定已锁定的互斥锁,或解锁未锁定的互斥锁,您可以将值驱动到 0-1 范围之外,从而使互斥锁不再正确执行。
它是 U/B,因为可以制作不受此问题影响的互斥锁,但并非每个系统都可以访问那种解决方案,因此如果您想要可移植的 C++ 代码,您必须有一个心理- increments/decrements 的简单计数模型,并且只锁定锁定或未锁定的互斥量。只解锁锁定的互斥体。