2010-08-24 56 views
5

我正在開發一個庫,在這裏我將各種任務分配給某些第三方庫,這些庫執行一些相對簡單或危險的平臺特定工作。 (具體來說,我正在編寫一個調用JIT編譯器的數學函數解析器,例如LLVM或libjit來構建機器代碼。)實際上,這些第三方庫有崩潰的傾向(部分原因是我的錯當然,但我仍然想要一些保險)。如何將工作/線程與崩潰隔離

因此,我希望能夠非常優雅地處理一個可怕的工作--SIGSEGV,SIGILL等 - 而不會將我的其他代碼(或者用戶的代碼庫函數)。要清楚的是,我不在乎這個特定的工作是否能夠繼續下去(我不會試圖修復崩潰的情況),在這樣的崩潰之後,我也不關心這些對象的狀態(我會放棄他們立即如果有崩潰)。我只希望能夠檢測到發生了崩潰,停止崩潰取出整個過程,停止調用任何崩潰並恢復執行。我們只需要執行continue;就可以了,並且可以繼續進行下一步操作(對於更多的上下文,此時的代碼是一個for循環,用於測試每個可用的JIT編譯器,其中一些編譯器可能會崩潰,如果他們這樣做,我只想執行continue;並繼續與測試另一個編譯器)。

目前,我有一個基於signal()的實現失敗非常可怕;當然,信號處理程序中的信號處理程序對longjmp()是未定義的行爲,並且信號處理程序幾乎預計以exit()terminate()結束。只是把代碼扔到另一個線程本身並沒有幫助,至少我迄今爲止測試過它的方式。我也無法破解一種使用C++異常來完成這項工作的方法。

那麼,隔離一組特定指令/線程/作業與崩潰的最佳方式是什麼?

回答

10

產卵一個新的過程。

+1

這是做到這一點的唯一方法。一個線程會在進程中的任何地方損壞內存,所以在SEGV之後,你不能保證你的內存不受影響。 – KeithB 2010-08-24 16:15:39

+0

感謝您的提醒。這裏幾乎肯定是正確的答案。我要閱讀fork()和company。 – 2010-08-25 18:54:18

5

當工作成功時,你收集什麼輸出?

我問,因爲如果輸出是低帶寬我會試圖在自己的過程中運行每個工作。

您啓動的這些崩潰作業中的每一個都有很大的機會破壞您的進程中其他位置使用的內存。

流程提供了最好的保護。

1

流程提供了最好的保護,但是你可能無法做到這一點。

如果您的線程的入口點是您寫入的函數(例如,Windows世界中的ThreadProc),那麼您可以將它們包裝在try{...}catch(...)塊中。如果您想通知發生了異常,那麼您可以將特定的錯誤代碼傳遞迴主線程或使用其他一些機制。如果您不僅要記錄發生了異常,而且要記錄異常,那麼您需要捕獲特定的異常類型並從中提取診斷信息,以便與主線程進行通信。網HRS歐洲:

int my_tempermental_thread() 
{ 
    try 
    { 
    // ... magic happens ... 
    return 0; 
    } 
    catch(const std::exception& ex) 
    { 
    // ... or maybe it doesn't ... 
    string reason = ex.what(); 
    tell_main_thread_what_went_wong(reason); 
    return 1; 
    } 
    catch(...) 
    { 
    // ... definitely not magical happenings here ... 
    tell_main_thread_what_went_wrong("uh, something bad and undefined"); 
    return 2; 
    } 
} 

請注意,如果你走這條路你運行沖水一旦發生異常主機過程中的風險。你說你不是想糾正這個問題,但是你怎麼知道惡性線程沒有吃掉你的堆棧? Catch-and-ignore是創建可怕混淆錯誤的好方法。

0

在Windows上,調用不可信代碼時可能可以使用VirtualProtect(YourMemory, PAGE_READONLY)。任何修改此內存的嘗試都會導致結構化異常。您可以安全地捕捉並繼續執行。但是,該庫分配的內存當然會泄漏,其他資源也一樣。 Linux的等價物是mprotect(YorMemory, PROT_READ),這會導致SEGV。