<mutex> 和 <condition_variable>的异常处理

Exception handling for <mutex> and <condition_variable>

本文关键字:lt gt 异常处理 variable mutex condition      更新时间:2023-10-16

假设

  1. 没有未定义的行为发生
  2. 不会发生死锁
  3. 互斥被正确的线程以正确的顺序锁定和解锁正确的次数
  4. 非递归互斥不是多次锁定的
  5. 锁定递归互斥不超过所有权的最大级别
  6. 没有传递给条件变量throw的谓词,并且
  7. 只有标准库提供的时钟、时间点和持续时间才能与std::互斥对象和条件变量一起使用

是否保证对不同类型的std::互斥和条件变量进行操作(而不是构造它们)不会引发任何异常(尤其是std::system_error类型的异常)?

例如,在使用以下方法的情况下:

void MyClass::setVariable() {
    std::lock_guard<std::mutex> const guard(m_mutex);
    m_var = 42; // m_var is of type int
    m_conditionVariable.notify_all();
}
void MyClass::waitVariable() {
    std::unique_lock<std::mutex> lock(m_mutex);
    m_conditionVariable.wait(lock, [this]() noexcept { return m_var == 42; });
}

假设noexcept安全吗?还是应该在调用站点周围写一些try-catch块?或者有什么需要注意的地方吗?

请考虑C++11、C++14及更高版本中所有类型的互斥和条件变量。

简短回答:没有(对不起)

如果底层同步对象无法执行其操作,则这些操作中的任何一个都将抛出std::system_error

这是因为同步原语的正确操作取决于:

  1. 可用的系统资源。

  2. 程序的某些其他部分不会使原始无效

尽管公平地说,如果(1)正在发生,那么可能是时候重新设计应用程序或在负载较低的机器上运行它了。

如果(2)正在发生,则程序在逻辑上不一致。

话虽如此,

还是应该在调用点周围写一些try-catch块?

也没有

您应该在以下条件下编写try/catch块:

  1. 当程序能够对错误情况做一些有用的事情时(例如修复它或询问用户是否想再试一次)

  2. 您想向错误添加一些信息并重新抛出它,以便提供诊断面包屑跟踪(例如嵌套异常)

  3. 您希望记录故障并继续。

否则,c++异常处理的全部意义在于,允许RAII处理资源重新获取,并允许异常在调用堆栈中向上流动,直到它找到一个想要处理它的处理程序

创建面包屑轨迹的示例:

void wait_for_object()
try
{
    _x.wait();  // let's say it throws a system_error on a loaded system
}
catch(...)
{
  std::throw_with_nested(std::runtime_error(__func__));
}

感谢T.C.现在提供的链接,我同意——您的代码应该是安全的。由于未来标准device_or_resource_busy将被删除,并且正如该问题的作者所说,这种情况不可能以任何合理的方式发生,因此lock只有两种可能性:

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

(13.2)--resource_deadlock_would_ecurse--如果实现检测到会出现死锁。

这两种情况都被你的先决条件排除在外。因此,您的代码应该可以安全地使用noexcept。