2016-05-13 93 views
11

假设异常处理<mutex>和<condition_variable>

  1. 没有发生不确定的行为,
  2. 无死锁发生,
  3. 互斥由正确的线程正确数量的锁定和解锁以正确的顺序次,
  4. 非递归互斥锁未锁定多次,
  5. 锁定递归互斥锁不超过maximum level of ownership,
  6. 没有谓词传递给条件变量扔,并
  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还是应该写一个各地callsites一些的try-catch块?或者有任何警告?

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

+0

你可以通过linux上的futex()实现来查找失败的条件:https://github.com/torvalds/linux/blob/master/kernel/futex.c#L3147 – Arvid

+1

'std :: condition_variable :: wait()'在C++中更改为'noexcept' 14。当重新获取锁定失败时,它现在只调用'std :: terminate()'。你可能想考虑一下。 – TFM

+0

@TFM我不同意。你能引用一些文件吗? –

回答

2

感谢的对link T.C。现在提供我会说是 - 你的代码应该是安全的。由于在未来的标准device_or_resource_busy将被删除,因为这个问题的作者说,这种情况不能以任何合理的方式发生那么只有有2种可能性lock抛出:

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

(13.2) - resource_deadlock_would_occur - 如果执行检测到 会发生死锁。

而这两种情况都被您的前提条件排除在外。所以你的代码应该安全使用noexcept。

+0

您可以提供任何真实的例子,说明在讨论的操作中可能抛出device_or_resource_busy的原因或位置? – jotik

+0

@jotik,我不能但它并不意味着它是不可能的。 – ixSci

+3

http://cplusplus.github.io/LWG/lwg-active.html#2309 –

9

简短的回答:否(对不起)

这些操作将抛出std::system_error如果底层同步对象未能履行其操作。

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

  1. 可用的系统资源。

  2. 的程序不是原始

虽然在公平无效,如果(1)正在发生的事情是其他部分也许是时候重新设计应用程序或加载较少的机器上运行它。

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

话虽这么说,

还是应该写一个各地callsites一些的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__)); 
} 
+0

我认为(2)已经被我的假设1和3考虑过了。但是你能举出一个真实的例子说明为什么(1)可能发生,即系统资源耗尽? – jotik

+1

@jotik我可以看到你的想法。基本上你问“有什么情况下我可以忽略系统同步函数的返回码”?事实上,几乎所有人几乎都在做,因为在实践中他们会失败的情况非常罕见。尽管如此,该标准指出这些函数可能会抛出异常,因此图书馆实施者可能会因为他们最能理解的原因而抛出异常。因此,我们必须假设一个例外是可能的。 –

+1

@ jotik并不是说每个异常都需要处理。如果这种情况非常罕见,并且只会发生在加载的系统上(程序的其他部分可能会失败),那么在main(或thread_main)中捕获异常并报告并中止几乎总是合理的。 –