C++ 对于具有互斥对象的类,无异常交换和移动
一般来说,声明掉期并移动noexcept是一种好的做法,因为它允许提供一些例外保证。 同时,编写线程安全类通常意味着添加一个互斥锁,以保护内部资源不受竞争的影响。 如果我想为这样一个类实现交换函数,简单的解决方案是以安全的方式锁定交换的两个参数的资源,然后执行资源交换,例如,在对这个问题的回答中清楚地回答了这个问题: 这种算法的问题在于互斥锁不是noexcept,因此严格来说,swap不能是noexcept。有没有一种解决方案可以安全地用互斥交换一个类的两个对象 我想到的唯一可能性是将资源存储为句柄,这样交换就变成了一个简单的指针交换,可以原子化地完成。 否则,可以将锁异常视为不可恢复的错误,它无论如何都会终止程序,但是这个解决方案就像是将灰尘放在地毯下的一种方式。 编辑: 从评论中可以看出,我知道互斥体引发的异常不是任意的,但问题可以重新表述为: 当互斥锁实际上是一个不可恢复的操作系统问题时,是否有可靠的实践来限制互斥锁可能引发的情况? 我想到的是,在交换算法中,检查要交换的两个对象是否不相同。这是一种明显的死锁情况,在最佳情况下会触发异常,但很容易检查。C++ 对于具有互斥对象的类,无异常交换和移动,c++,mutex,noexcept,C++,Mutex,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不允许的错误,但发生这种情况时