【问题标题】:How to handle a ctrl-break signal in a command line interface如何在命令行界面中处理 ctrl-break 信号
【发布时间】:2010-09-15 22:26:54
【问题描述】:

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

编辑:我必须为我之前的解释道歉,显然我没有很好地解释它。再来一次……

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

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

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

【问题讨论】:

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


    【解决方案1】:

    在 *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】:

      一个更好的线程安全的 *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);  
      

      【讨论】:

        【解决方案3】:

        好的 - 这在 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;
        }
        

        【讨论】:

        • 注意:在 Windows 上,点击关闭按钮会产生 sig 码 SIGBREAK (ctrl-break)
        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          在 Windows 中:SetConsoleCtrlHandler

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-01-08
            • 2016-07-16
            • 1970-01-01
            • 2011-11-11
            • 2012-05-14
            • 2014-08-16
            • 2012-03-20
            相关资源
            最近更新 更多