1. 程式人生 > >Linux下C/C++程式處理Ctrl+C的例子

Linux下C/C++程式處理Ctrl+C的例子

遇到一個場景:程式要讀入檔案,而使用者在使用檔案時是用/dev/urandom重定向作為輸入的。(好吧這個使用者就是測試我們作業的助教……)而/dev/urandom顯然是沒有EOF的,只有用Ctrl+C的方法結束輸入。但是Ctrl+C也會同時結束程式,造成不用刻預測的結果。

因此,程式必須設法獲知Ctrl+C的發生並進行處理。在Linux下,按下Ctrl+C後,程式會收到一個訊號SIGINT;這時作業系統預設會結束程式。如果程式不想被預設處理,就要設定對SIGINT訊號的處理函式(Handler)。下面是一個簡單的例子:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h> // signal functions
volatile sig_atomic_t flag = 0;
static void my_handler(int sig){ // can be called asynchronously
  flag = 1; // set flag
}

int main(){
  // Register signals 
  signal(SIGINT, my_handler); 
  //      ^          ^
  //  which-signal   |-- which user defined function registered
  while(1)  
    if(flag){ // my action when signal set it 1
        printf("\n Signal caught!\n");
        printf("\n default action it not termination!\n");
        flag = 0;
    }     
  return 0;
}
(來源:http://stackoverflow.com/questions/17766550/ctrl-c-interrupt-event-handling-in-linux)

如上面程式所示,一般是在一個迴圈中檢測一個標誌變數flag,而這個flag只在訊號處理函式中改變。在這裡,my_handler()函式會在Ctrl+C按下後被呼叫,並設定flag。注意,由於我們自己設定了Ctrl+C的處理函式,系統就不會再按預設行為結束程式了。因此flag的變化會在迴圈中被檢測到,並作出響應。

需要注意的是,網上很多例子中出於演示的方便,在訊息處理函式中使用printf()。這樣是不安全的:設想程式在正常呼叫printf的過程中收到了Ctrl+C,那麼訊號處理函式就會再呼叫一次printf,這有有造成錯誤的可能。有一些函式經過專門的設計可以安全地在訊號處理函式中使用。

具體的解釋可以參考:Matthew N, Stones R. Beginning Linux Programming[M]. John Wiley & Sons, 2011. 中的 Chapter 11: Processes and Signals。