2016-05-13 88 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)中捕獲異常並報告並中止幾乎總是合理的。 –