2011-07-23 50 views
14

我有一個簡單的程序,使用Qt框架。 它使用QProcess執行RAR並壓縮一些文件。在我的計劃,我趕上SIGINT和在我的代碼做一些事情,當它occures:子進程收到父母的SIGINT

signal(SIGINT, &unix_handler); 

當SIGINT occures,我檢查,如果RAR過程就完成了,如果不是我會等待...問題是(我認爲)RAR進程也得到了SIGINT,這是爲我的程序設計的,它在壓縮所有文件之前退出。

有沒有辦法運行RAR進程,以便在我的程序收到它時不會收到SIGINT?

謝謝

+0

什麼操作系統? – Nemo

+0

目前我在Debian 5.0.8上進行測試 – xx77aBs

回答

25

如果您在Unix系統上使用Ctrl-c生成SIGINT,則信號將發送到整個process group

您需要使用setpgidsetsid將子進程放入不同的進程組,以便它不會接收控制終端生成的信號。

[編輯]

請務必仔細閱讀setpgid頁面的基本原理部分。在這裏插入所有潛在的競爭條件是有點棘手的。

要保證沒有SIGINT將交付給你的孩子的過程100%,你需要做的是這樣的:

#define CHECK(x) if(!(x)) { perror(#x " failed"); abort(); /* or whatever */ } 
/* Block SIGINT. */ 
sigset_t mask, omask; 
sigemptyset(&mask); 
sigaddset(&mask, SIGINT); 
CHECK(sigprocmask(SIG_BLOCK, &mask, &omask) == 0); 

/* Spawn child. */ 
pid_t child_pid = fork(); 
CHECK(child_pid >= 0); 
if (child_pid == 0) { 
    /* Child */ 
    CHECK(setpgid(0, 0) == 0); 
    execl(...); 
    abort(); 
} 
/* Parent */ 
if (setpgid(child_pid, child_pid) < 0 && errno != EACCES) 
    abort(); /* or whatever */ 
/* Unblock SIGINT */ 
CHECK(sigprocmask(SIG_SETMASK, &omask, NULL) == 0); 

嚴格地說,這些步驟每一個需要。如果用戶在呼叫fork後立即點擊Ctrl-C,則必須阻止該信號。如果execl發生在父母有時間做任何事之前發生,您必須在子女中撥打setpgid。如果父級運行,並且有人在子級有時間做任何事情之前點擊Ctrl-C,則必須在父級中調用setpgid

上面的序列很笨拙,但它確實能夠處理100%的競爭條件。

+0

非常感謝。我認爲這是我的問題的答案。我會盡快嘗試;) – xx77aBs

+0

它的工作,我剛剛添加正確的包括和這一行:setpgid(rar.pid(),0); – xx77aBs

+0

沒問題。請注意,'setpgid'充滿了競爭條件,正確使用它有點微妙。我已經更新了我的答案,使其更加完整。 – Nemo

0

你在做什麼你的處理程序?只有某些Qt函數可以從unix信號處理程序中安全地調用。文檔中的This page標識它們是什麼。

主要的問題是處理程序將在主Qt事件線程之外執行。該頁面還提出了一個處理這個問題的方法。我更喜歡讓處理程序將「自定義事件」「發佈」到應用程序並進行處理。我發佈了一個描述如何實現自定義事件here的答案。

+0

感謝您瀏覽此頁面,我並不知道它。我只是調用quit並等待我的線程,然後退出應用程序。它適用於除RAR以外的所有內容,所以我不認爲這是問題所在。但我會閱讀這個頁面。再次感謝 – xx77aBs