如果我想为这样的类实现交换函数,直接的解决方案是以安全的方式锁定交换的两个参数的资源,然后执行资源交换,例如,在这个问题的答案中已经清楚地回答了。为使用std::mutex的类实现交换功能 .
这样的算法的问题是,mutex锁不是noexcept,因此严格来说,swap不能是noexcept。有没有一种解决方案可以安全地交换一个类的两个对象与一个mutex?
我想到的唯一可能是将资源存储为一个句柄,这样交换就变成了一个简单的指针交换,可以原子化地完成.否则可以将锁异常视为不可恢复的错误,无论如何都应该终止程序,但这个解决方案感觉只是将灰尘放在地毯下的一种方法。
EDIT:正如评论中所说,我知道由mutexes引发的异常不是... ... 任意 但是,问题就可以这样改写了。
是否有稳健的做法来限制mutex可能引发的情况,当它实际上是一个不可恢复的操作系统问题时? 我想到的是,在交换算法中,检查两个要交换的对象是否不一样。 这是一个明显的死锁情况,在最好的情况下会引发异常,但很容易检查。这是一个明显的死锁情况,在最好的情况下会触发一个异常,但可以很容易地检查出来.是否有其他类似的触发器,可以安全地检查,使交换函数健壮,实际上没有except所有重要的情况?
在POSIX系统中,常见的是 std::mutex
包裹 pthread_mutex_t
锁定和解锁功能可能会在以下情况下失效。
在C++中,以上两个都是UB,甚至不保证POSIX会返回。在Windows中,这两个都是UB,如果 std::mutex
是对 SRWLOCK
所以看来,允许 lock
和 unlock
函数抛出是为了发出程序错误的信号,而不是让程序员期待并处理这些错误。
这一点可以从推荐的锁定模式中得到证实:析构器的 ~unique_lock
是 noexcept(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。质量 的实施 lock
和 unlock
绝不应该扔。
在常见的实现中,至少有一种可能是低质量的。std::mutex
实现在... CRITICAL_SECTION
在旧版本的Windows中(我认为是Windows XP和更早的版本),可以在失败后抛出在争夺过程中懒惰地分配内部事件。另一方面,即使是更早的版本也会在初始化时分配这个事件,以防止以后失败,所以 std::mutex::mutex
构造函数可能需要扔在那里(即使它是 noexcept(true)
在标准中)。)