2008-10-08 55 views
5

在開始之前,我想澄清一下,這不是一個命令行工具,而是一個通過它自己的命令行界面接受命令的應用程序。如何在命令行界面中處理ctrl-break信號

編輯:我必須對我之前的解釋表示歉意,顯然我沒有很好的解釋它。還有一次...

我正在構建一個接受用戶命令的命令行界面應用程序。我有一個信號處理程序設置來捕捉信號,然後設置一個標誌,我需要終止應用程序。我遇到的問題是我能找到的所有控制檯功能都是阻塞的,這意味着我無法檢測到我需要退出控制檯處理循環,直到用戶按下某個鍵(或輸入,具體取決於功能)。

有沒有一些標準的方式我可以做非塊控制檯交互,或者是否有一個優雅的方式來構建程序,以便如果我只是從信號線程終止,一切都將得到妥善處理和釋放(請不要誤解這一點,我知道如何使用鎖定和釋放信號線程中的資源來完成這項工作,但這可能會變得麻煩,所以我寧願避免它)

希望解釋更有意義...

回答

6

在* nix,你可以使用signal函數註冊一個信號處理程序:現在


#include <signal.h> 

void signal_handler(int sig) 
{ 
    // Handle the signal 
} 

int main(void) 
{ 
    // Register the signal handler for the SIGINT signal (Ctrl+C) 
    signal(SIGINT, signal_handler); 
    ... 
} 

,只要有人點擊Ctrl + C鍵,信號處理程序將被調用。

0

在基於* nix的系統上,您可能並不需要信號處理程序來使其工作。你可以指定你想忽略SIGINT調用

int main(void) 
{ 
    // Register to ignore the SIGINT signal (Ctrl+C) 
    signal(SIGINT, SIG_IGN); 

    while(1) 
    { 
    retval = my_blocking_io_func(); 
    if(retval == -1 && errno == EINTR) 
    { 
     // do whatever you want to do in case of interrupt 
    } 
    } 
} 

這個工作的重要方式是認識到非阻塞函數會被打斷。通常情況下,您會意識到阻塞函數失敗(例如,read())並重新嘗試該函數。如果它是一些其他值,你會採取適當的錯誤相關的行動。

8

確定 - 這對我來說在Windows上工作&是便攜式的 - 注意#ifdef SIGBREAK - 這不是標準信號。

#include <csignal> 
#include <iostream> 
#include <ostream> 
#include <string> 
using namespace std; 

namespace 
{ 
    volatile sig_atomic_t quit; 

    void signal_handler(int sig) 
    { 
     signal(sig, signal_handler); 
     quit = 1; 
    } 
} 

int main() 
{ 
    signal(SIGINT, signal_handler); 
    signal(SIGTERM, signal_handler); 
#ifdef SIGBREAK 
    signal(SIGBREAK, signal_handler); 
#endif 
    /* etc */ 

    while (!quit) 
    { 
     string s; 
     cin >> s; 
     cout << s << endl; 
    } 
    cout << "quit = " << quit << endl; 
} 
+1

注:在Windows中,點擊關閉按鈕將提高SIG代碼`SIGBREAK`(CTRL-打破) – 56ka 2014-08-12 13:35:43

0

更好的* nix的解決方案,它是線程安全的方法是使用pthread_sigmask()而不是信號的()。
例如,你這是怎麼SIGNORE SIGINT,SIGTERM,並且在當前線程和未來SIGPIPE產生的線程:

sigset_t waitset; 
sigemptyset(&waitset); 
sigaddset(&waitset, SIGINT); 
sigaddset(&waitset, SIGTERM); 
sigaddset(&waitset, SIGPIPE); 
pthread_sigmask(SIG_BLOCK, &waitset, NULL);