C++ 对于具有互斥对象的类,无异常交换和移动

C++ 对于具有互斥对象的类,无异常交换和移动,c++,mutex,noexcept,C++,Mutex,Noexcept,一般来说,声明掉期并移动noexcept是一种好的做法,因为它允许提供一些例外保证。 同时,编写线程安全类通常意味着添加一个互斥锁,以保护内部资源不受竞争的影响。 如果我想为这样一个类实现交换函数,简单的解决方案是以安全的方式锁定交换的两个参数的资源,然后执行资源交换,例如,在对这个问题的回答中清楚地回答了这个问题: 这种算法的问题在于互斥锁不是noexcept,因此严格来说,swap不能是noexcept。有没有一种解决方案可以安全地用互斥交换一个类的两个对象 我想到的唯一可能性是将资源存储为

一般来说,声明掉期并移动noexcept是一种好的做法,因为它允许提供一些例外保证。 同时,编写线程安全类通常意味着添加一个互斥锁,以保护内部资源不受竞争的影响。 如果我想为这样一个类实现交换函数,简单的解决方案是以安全的方式锁定交换的两个参数的资源,然后执行资源交换,例如,在对这个问题的回答中清楚地回答了这个问题:

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

我想到的唯一可能性是将资源存储为句柄,这样交换就变成了一个简单的指针交换,可以原子化地完成。 否则,可以将锁异常视为不可恢复的错误,它无论如何都会终止程序,但是这个解决方案就像是将灰尘放在地毯下的一种方式。 编辑: 从评论中可以看出,我知道互斥体引发的异常不是任意的,但问题可以重新表述为:

当互斥锁实际上是一个不可恢复的操作系统问题时,是否有可靠的实践来限制互斥锁可能引发的情况? 我想到的是,在交换算法中,检查要交换的两个对象是否不相同。这是一种明显的死锁情况,在最佳情况下会触发异常,但很容易检查。
有没有其他类似的触发器可以安全地检查,以使交换函数健壮,并且几乎不例外于所有重要的情况?

在POSIX系统上,
std::mutex
通常是
pthread\u mutex\t
的薄包装,在以下情况下,锁定和解锁功能可能会失败:

  • 试图获取已拥有的锁
  • 互斥对象未初始化或已被销毁

以上两个都是C++中的UB,甚至不能保证由POSIX返回。在Windows上,如果

std::mutex
SRWLOCK
的包装器,则两者都是UB

因此,似乎允许
lock
unlock
函数抛出的主要目的是发出程序错误的信号,而不是让程序员期望并处理它们

建议的锁定模式证实了这一点:析构函数是
noexcept(true)
,但应该调用
unlock
,即
noexcept(false)
。这意味着如果
unlock
函数引发异常,则整个程序将通过
std::terminate
终止

本标准还提到:

成员报告的错误代码(如果有)的错误条件 互斥类型的功能应为:

(4.1)
资源不可用\u请重试
-如果有任何本机句柄类型 不可用

(4.2)-
不允许操作
-如果螺纹没有 执行该操作的权限

(4.3)
无效的\u参数
-如果任何本机句柄类型被操纵为 部分互斥结构不正确

理论上,您可能会遇到
操作\u不允许的
错误,但发生这种情况的情况并未在标准中真正定义

因此,除非您在与
std::mutex
使用相关的程序中导致UB,或者在某些特定于操作系统的场景中使用mutex,否则
lock
unlock
的高质量实现决不能抛出


在常见的实现中,至少有一种可能是低质量的:
std::mutex
在旧版本的Windows(我认为Windows XP和更早版本)中的
CRITICAL_部分
上实现,在争用期间未能延迟分配内部事件后可能抛出。另一方面,甚至更早的版本也在初始化期间分配了此事件以防止以后失败,因此
std::mutex::mutex
构造函数可能需要抛出此事件(即使在标准中它是
noexcept(true)
).

在POSIX系统上,
std::mutex
通常是
pthread\u mutex\t
的薄包装,在以下情况下,锁定和解锁功能可能会失败:

  • 试图获取已拥有的锁
  • 互斥对象未初始化或已被销毁

以上两个都是C++中的UB,甚至不能保证由POSIX返回。在Windows上,如果

std::mutex
SRWLOCK
的包装器,则两者都是UB

因此,似乎允许
lock
unlock
函数抛出的主要目的是发出程序错误的信号,而不是让程序员期望并处理它们

建议的锁定模式证实了这一点:析构函数是
noexcept(true)
,但应该调用
unlock
,即
noexcept(false)
。这意味着如果
unlock
函数引发异常,则整个程序将通过
std::terminate
终止

本标准还提到:

成员报告的错误代码(如果有)的错误条件 互斥类型的功能应为:

(4.1)
资源不可用\u请重试
-如果有任何本机句柄类型 不可用

(4.2)-
不允许操作
-如果螺纹没有 执行该操作的权限

(4.3)
无效的\u参数
-如果任何本机句柄类型被操纵为 部分互斥结构不正确

理论上,您可能会遇到
操作\u不允许的
错误,但发生这种情况时