除了交换和移动之外,不允许使用mutexes的类。

问题描述 投票:0回答:1

如果我想为这样的类实现交换函数,直接的解决方案是以安全的方式锁定交换的两个参数的资源,然后执行资源交换,例如,在这个问题的答案中已经清楚地回答了。为使用std::mutex的类实现交换功能 .

这样的算法的问题是,mutex锁不是noexcept,因此严格来说,swap不能是noexcept。有没有一种解决方案可以安全地交换一个类的两个对象与一个mutex?

我想到的唯一可能是将资源存储为一个句柄,这样交换就变成了一个简单的指针交换,可以原子化地完成.否则可以将锁异常视为不可恢复的错误,无论如何都应该终止程序,但这个解决方案感觉只是将灰尘放在地毯下的一种方法。

EDIT:正如评论中所说,我知道由mutexes引发的异常不是... ... 任意 但是,问题就可以这样改写了。

是否有稳健的做法来限制mutex可能引发的情况,当它实际上是一个不可恢复的操作系统问题时? 我想到的是,在交换算法中,检查两个要交换的对象是否不一样。 这是一个明显的死锁情况,在最好的情况下会引发异常,但很容易检查。这是一个明显的死锁情况,在最好的情况下会触发一个异常,但可以很容易地检查出来.是否有其他类似的触发器,可以安全地检查,使交换函数健壮,实际上没有except所有重要的情况?

c++ mutex noexcept
1个回答
2
投票

在POSIX系统中,常见的是 std::mutex 包裹 pthread_mutex_t锁定和解锁功能可能会在以下情况下失效。

  • 试图获取已经拥有的锁
  • 突变对象未被初始化或已被销毁。

在C++中,以上两个都是UB,甚至不保证POSIX会返回。在Windows中,这两个都是UB,如果 std::mutex 是对 SRWLOCK

所以看来,允许 lockunlock 函数抛出是为了发出程序错误的信号,而不是让程序员期待并处理这些错误。

这一点可以从推荐的锁定模式中得到证实:析构器的 ~unique_locknoexcept(true)但应该是叫 unlock 也就是 noexcept(false). 这意味着如果异常由 unlock 函数,整个程序会被 std::terminate.

标准中也提到了这一点。

变位类型的成员函数报告的错误代码的错误条件(如果有的话)应是:

(4.1) — resource_unavailable_try_again - 如果任何本地手柄类型不可用。

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

(4.3) — invalid_argument - 如果任何作为mutex构造一部分的本地句柄类型是不正确的。

理论上你可能会遇到 operation_not_permitted 错误,但标准中并没有真正定义这种情况的发生。

所以,除非你在你的程序中造成了与 std::mutex 的使用,或者在一些操作系统特定的场景下使用mutex。质量 的实施 lockunlock 绝不应该扔。

在常见的实现中,至少有一种可能是低质量的。std::mutex 实现在... CRITICAL_SECTION 在旧版本的Windows中(我认为是Windows XP和更早的版本),可以在失败后抛出在争夺过程中懒惰地分配内部事件。另一方面,即使是更早的版本也会在初始化时分配这个事件,以防止以后失败,所以 std::mutex::mutex 构造函数可能需要扔在那里(即使它是 noexcept(true) 在标准中)。)

© www.soinside.com 2019 - 2024. All rights reserved.