如何在命令行界面中处理ctrl-break信号

时间:2008-10-08 05:02:28

标签: c++ signals command-line-interface

在开始之前,我想澄清一下,这不是一个命令行工具,而是一个通过它自己的命令行界面接受命令的应用程序。

编辑:我必须为之前的解释道歉,显然我没有做好解释它的工作。再来一次......

我正在构建一个接受用户命令的命令行界面应用程序。我有一个信号处理程序设置来捕获信号,然后设置我需要终止应用程序的标志。我遇到的问题是我能找到的所有控制台功能都是阻塞的,这意味着我无法检测到我需要退出控制台处理循环,直到用户按下某个键(或输入,具体取决于函数) )。

是否有一些标准的方法我可以做非块控制台交互,或者是否有一种优雅的方式来构建程序,这样如果我只是从信号线程终止,那么一切都将被正确处理和释放(请不要我不明白这一点,我知道如何使用锁定和释放信令线程中的资源来实现这一点,但这可能会变得混乱,所以我宁愿避免使用它。)

希望这种解释更有意义......

5 个答案:

答案 0 :(得分:8)

好的 - 这适用于Windows和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 :(得分: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,就会调用你的信号处理程序。

答案 2 :(得分:2)

在Windows中:SetConsoleCtrlHandler

答案 3 :(得分:1)

在基于* 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())并重新尝试该功能。如果是其他值,您将采取相应的错误相关操作。

答案 4 :(得分:0)

线程安全的更好的* nix解决方案是使用pthread_sigmask()而不是signal() 例如,这是您在当前线程和未来生成的线程中签署SIGINT,SIGTERM和SIGPIPE的方式:

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