2011-09-11 46 views
11

Linux下C捕獲kill信號我使用套接字,數據庫連接和喜歡的過程。它基本上是一個服務器進程,用於在傳感器數據和Web界面之間進行中繼,因此,確保應用程序(如果遇難​​)優雅地終止非常重要。爲正常終止

如何處理意外的異常,如segfaults(至少用於調試)以及殺死信號,以便我可以關閉任何連接並停止任何線程運行,這樣進程不會留下任何混亂的使用?

+0

記住繼續運行,甚至清理,分段故障後,可能會造成危險。 – icktoofay

+0

'man sigaction' –

+1

另外請記住,你不能捕殺信號。 – Gabe

回答

7

您可以安裝信號處理程序來捕獲信號 - 但是,只有99%的情況下,您只想退出並讓Linux操作系統負責清理工作 - 它會愉快地關閉所有文件,套接字,空閒內存和關閉線程。

所以,除非有什麼特別,你想做的事,就像插座發送消息,那麼你應該從進程剛剛退出,而不是試圖趕上信號。

+0

我認爲你就在這裏...應用程序的可靠性對我而言更重要,並且做着瘋狂的事情信號可能不好。當段錯誤發生時,如果我得到coredumps,它是否告訴你段錯誤發生在哪裏? – user623879

+0

調用堆棧告訴你是seg-fault發生,假設調用堆棧沒有被破壞 - 這裏的問題:http://stackoverflow.com/questions/105659/how-can-one-grab-a- stack-trace-in-c討論如何獲得堆棧跟蹤 – Soren

+0

偉大的建議。此規則的一個例外是當程序關閉時(在embeeded系統中)需要清理或更改硬件時。 – Havok

6

我有時想獲得SIGSEGV回溯,捕捉部分是這樣:

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 

void sig_handler(int); 

int main() { 
    signal(SIGSEGV, sig_handler); 
    int *p = NULL; 
    return *p; 
} 

void sig_handler(int sig) { 
    switch (sig) { 
    case SIGSEGV: 
     fprintf(stderr, "give out a backtrace or something...\n"); 
     abort(); 
    default: 
     fprintf(stderr, "wasn't expecting that!\n"); 
     abort(); 
    } 
} 

你要非常小心處理這些事情,例如確保你不能觸發另一個信號。

+1

使用'ulimit'來獲得核心轉儲並獲得堆棧跟蹤更方便嗎? –

+0

不熟悉那種方法,你能詳細說明一下嗎?我只用這個東西來調試btw,即我犯了一個錯誤,並希望看到信號來自哪裏。 – daniel

+2

你真的不應該使用'signal'。多年來,建議不要這樣做,而是使用'sigaction'。來自'man signal':* signal()的行爲因Unix版本而異,並且在不同版本的Linux中歷史上也有所不同。避免使用它:改用sigaction(2)。*。我並不低調......但它很接近。你不應該推薦任何人使用它。 –

10

捕獲信號是困難的。你必須要小心。您的第一步是使用sigaction爲所需信號安裝信號處理程序。

  • 選擇一組信號來響應並選擇它們對於您的過程意味着什麼。例如,SIGTERM退出,重新啓動SIGHUPSIGUSR1重新加載配置等

  • 不要試圖對所有信號作出反應,也不要試圖信號,表示你的程序中的錯誤後,「清理」。 SIGKILL不能被捕獲。 SIGSEGV,SIGBUS,和其他人一樣,除非你有很好的理由,否則不應該被抓到。如果你想調試,然後提高核心轉儲的ulimit - 將調試器附加到核心映像比你或我可以編碼的任何東西都要有效得多。 (如果你嘗試SIGSEGV或類似的東西清理後,意識到清理代碼可能會導致額外的SIGSEGV和事情會變得糟糕的很快,只是避免全亂了,讓SIGSEGV終止你的程序。)

  • 你如何處理信號是棘手的。如果您的應用程序有一個主循環(例如,selectpoll),則信號處理程序可以只設置一個標誌或字節寫入專用管信號的主循環退出。您也可以使用siglongjmp跳出信號處理程序,但這很難正確並且通常不是您想要的。

如果不知道應用程序的結構和功能如何,很難推薦一些東西。

還記得信號處理程序本身應該做的幾乎沒有。來自信號處理器的許多功能都不安全。