簡體   English   中英

std::async 應該尊重拋出的錯誤嗎?

[英]Should std::async respect thrown errors?

我試圖了解異常是如何異步處理的——我有一個網絡服務器,其中包含一個用於處理請求(uWebsockets)的 lambda 處理程序,它一直在崩潰。 為了模擬我使用 std::async 的場景

void call(function<void()> fn) {
  std::async([&fn]{
    fn();
  });
}

int main() {
  try {
    call([](){
      throw std::runtime_error("Oops");
    });
  } catch (std::runtime_error &e) {
    cout<<"Caught the error"<<endl;
  }
  std::this_thread::sleep_for(std::chrono::milliseconds(100000));
} 

似乎在 std::async 內運行 function 會導致運行時錯誤永遠不會執行......程序就像什么都沒發生一樣退出......為什么會這樣?

讓我們一步一步來。 讓我們從std::async所做的定義開始。 它:

異步運行 function f(可能在單獨的線程中

“可能”這個詞在這里讓人分心,但重點是這里將涉及不同的執行線程 出於所有實際原因,獲得std::async的 function 可以,並且在現代 C++ 實現中,它將在新的執行線程中運行。

首先,擁有不同執行線程的真正原因是它們完全獨立於它們的父執行線程。 不同的執行線程必須正確地執行排序操作,以便在它們之間以某種形式或方式相互交換信息。

  try {

  } catch (std::runtime_error &e) {
    cout<<"Caught the error"<<endl;
  }

異常的概念,以及trycatch與它們的關系,在您的普通 C++ 教科書中通過解釋try / catch如何捕獲try / catch塊內發生的異常來介紹。 一旦執行離開try / catch塊,異常處理就不再有效,並且不會捕獲任何異常(除非執行在另一個try / catch塊內)。

結合執行線程的概念和異常處理的典型解釋,您可能會或可能不會立即清楚,您必須得出一個不可避免的結論,即您只能捕獲從同一執行線程拋出的異常。

此外,在顯示的代碼中,當另一個執行線程中的異常被拋出時,絕對沒有任何東西可以保證原始執行線程仍然在try / catch塊內。 事實上,當異常被拋出時,父執行線程很可能已經離開了原始的try / catch塊並且它是sleep_for -ing。 離開try / catch塊后,您將無法再捕獲異常。

但是即使原始執行線程仍在try / catch塊中,這也不會產生任何影響,因為拋出的異常只能被同一個執行線程捕獲,但是由std::async執行的 function 將運行在一個完全不同的執行線程中。

編輯

std::async([&fn]{

這通過引用捕獲fn fn是一個 function 參數,它超出 scope 並在 function 返回時被破壞,但不能保證新的執行線程會在此之前引用它。 出於異常處理機制的目的(以及std::async本身如何處理拋出的異常),這無關緊要,但這仍然需要修復。

您在主線程中沒有觀察到異常的原因是從不查詢async返回的future值。 如果您像這樣擴展call的實現:

void call(function<void()> fn) {
  std::async([&fn]{
    fn();
  }).get();    // .get() added here
}

然后觀察到異常,因為 function 等待結果。

即使沒有這種修改,盡管@SamVarshavchik 的分析, call仍然具有明確定義的行為,因為async返回的future在特定方面是特殊的:它的析構函數等待 function 完成(請參閱那里的注釋部分)。 也就是說,直到被調用線程完成(拋出異常), call才會返回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM