2010-09-07 78 views
3

我試圖讓我的程序忽略Ctrl + C在unix中,這似乎工作,問題是它不斷寫入「語法錯誤」。下面是代碼sigset:忽略Unix中的ctrl-c

extern "C" void ignore(int sig) 
{    
    fprintf(stderr, "\n"); // Print a new line 
    // This function does nothing except ignore ctrl-c 
} 

int main() 
{   
    // For ctrl-c 
    sigset(SIGINT, ignore); 

    while (1) { 
     getUserInput(); 
    }  

    return 0; 
} 

每次我打按Ctrl +ç通過getUserInput再次運行,這是預期的行爲,但它寫道:「語法錯誤」的可能。我檢查並執行「忽略」函數,一旦它被執行,然後打印錯誤信息,我不知道爲什麼。

有沒有人有任何線索?

非常感謝你,

Jary

+4

如果這是C,爲什麼'extern「C」'? – alternative 2010-09-07 22:29:56

+2

請發佈一個完整的,自包含的程序,可以編譯。我在這裏看到至少有兩件事可能是你的問題,但如果沒有完整的測試用例,我不能確定。 – zwol 2010-09-07 22:33:16

+0

如果這是新代碼,你可能想使用'sigaction'; 'sigset'是POSIX之前版本,不推薦使用 – 2010-09-07 22:35:27

回答

7

請勿使用sigset()。儘管它在POSIX 2008中,但它被標記爲過時 - 並且在線程程序中也不安全。

然後,您可以選擇signal(),它受ISO C祝福,但具有一些不良特性,並且它是POSIX系統中首選解決方案。

信號處理的一個關鍵點是確保您不會在進入程序時捕獲任何被忽略的信號 - 除非您知道調用者無法做的事情(例如您需要爲死亡的孩子捕獲SIGCHLD信號)。

這導致標準的配方,因爲時間宣揚自古以來,爲signal()

if (signal(SIGINT, SIG_IGN) != SIG_IGN) 
    signal(SIGINT, ignore); 

或者,sigaction()

struct sigaction new_sa; 
struct sigaction old_sa; 
sigfillset(&new_sa.sa_mask); 
new_sa.sa_handler = SIG_IGN; 
new_sa.sa_flags = 0; 

if (sigaction(SIGINT, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN) 
{ 
    new_sa.sa_handler = ignore; 
    sigaction(SIGINT, &new_sa, 0); 
} 

既然你不向我們展示getUserInput()功能,有我們無法預測爲什麼您會看到「語法錯誤」。但是,如果您在工作時有語法,很可能是您的讀取沒有返回有效數據,並且解析器不滿意緩衝區中留下的內容以供處理。

+0

感謝您的信息。的確,getUserInput是一個很大的工作語法,我相信你是對的。謝謝! – Jary 2010-09-07 23:04:16

1

「語法錯誤」消息必須從getUserInput功能即將(或東西它調用,當然) - 你可以調查由具有該功能的打印瞭解它正在接受什麼以及它爲什麼抱怨。

請注意,忽略信號的規範方式是使用預定義的SIG_IGN作爲信號處理程序。例如 sigset(SIGINT, SIG_IGN)

5

(注:更多的便攜性,你應該使用signal()(C標準庫)或sigaction()(POSIX),而不是sigset(),但我不認爲這裏這就是問題所在)

你不真的忽略了這裏的信號;你正在捕獲它並採取自己的行動 - 但是由於中斷,系統調用可能會返回一個錯誤。

例如也許你已經導致read系統調用失敗,出現EINTR。我懷疑真正的問題是getUserInput()裏面的一些代碼沒有處理這個錯誤情況。

您可以通過處理程序設置爲特殊值SIG_IGN,這應該與任何sigset()signal()sigaction()工作完全忽略信號。

+0

非常感謝!這解決了我的問題。 – Jary 2010-09-07 22:50:54

1

ignore()確實比沒有更多。

在UNIX上運行此代碼時,在執行getUserInput()的同一線程上異步傳送SIGINT。如果SIGINT到達,而getUserInput()正在訪問stderr,則行爲未定義,因爲fprintf()通常不被設計爲可重入。 (但是,行爲可能包含亂碼和/或重複輸出。在SIGINT交付之前,您的程序是否打印了「語法錯誤」?)CERTGNU libc有關於此的更多信息。

如果您在Win32上運行此代碼,SIGINT將被異步傳遞in a separate thread