6

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

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

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

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

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

4

5 回答 5

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;
}
于 2008-10-08T06:54:55.850 回答
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,您的信号处理程序就会被调用。

于 2008-10-08T05:07:21.310 回答
3

在 Windows 中:SetConsoleCtrlHandler

于 2008-10-08T05:05:46.010 回答
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())并重新尝试该函数。如果它是其他值,您将采取适当的与错误相关的操作。

于 2008-10-08T05:28:40.737 回答
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);  
于 2013-09-03T13:31:49.740 回答