【问题标题】:Determine system halt in c++在 C++ 中确定系统停止
【发布时间】:2012-06-28 15:10:19
【问题描述】:

好吧,我正在开发一个用 C++ 编写的程序,它作为守护进程运行。它主要针对 Linux 用户,但我希望也包括 Windows(作为服务运行)和 Mac 用户。

我希望守护程序在手动关闭时记录。但是,它应该记录由于系统停止或重新启动而导致的系统关闭。

目前我已经屏蔽了所有信号并使用 sigaction() 实现了某种处理。在记录关闭之前,一个函数也在检查系统的运行级别,如果是 0, 1 0r 6 则省略记录。检查运行级别的方法是运行命令“runlevel”并处理输出。

我的问题是运行级别并不总是我所期望的。我正在运行 Ubuntu,像往常一样登录时,我处于运行级别 2,重新启动时也是如此。停止时,我有时会从“运行级别”中得到任何输出。不同的 Linux 发行版使用自己的运行级别,因此它不是最佳的可移植性。

那么有没有更好的方法来确定系统是否正在停止?此外,是否有更好的方法来捕捉中断,例如通过异常处理等?

如果对这里有任何帮助,我将粘贴代码的 sn-p。用 C++ 编写,使用 Poco C++ libraries

void MainApplication::signalHandler(int sig) {
#if defined(POCO_OS_FAMILY_UNIX)
    switch(sig) {
        case -1:
            struct sigaction act;
            act.sa_handler = signalHandler;
            sigemptyset(&act.sa_mask);
            act.sa_flags = 0;
            sigaction(SIGINT, &act, 0); //Better way to do this?
            sigaction(SIGQUIT, &act, 0);
            sigaction(SIGKILL, &act, 0);
            sigaction(SIGTERM, &act, 0);
            sigaction(SIGHUP, &act, 0);
            sigaction(SIGSTOP, &act, 0);
            sigaction(SIGTSTP, &act, 0);
            sigaction(SIGCONT, &act, 0);
            sigaction(SIGUSR1, &act, 0);
            sigaction(SIGUSR2, &act, 0);
            break;
        case SIGINT:
        case SIGQUIT:
        case SIGTSTP:
        case SIGHUP:
        case SIGKILL:
        case SIGTERM:
            //Log Shutdown!
            if (!isHalting())
                _instance->_database->logBypass(BYPASS_SHUTDOWN);
            terminateNicely(true);
            break;
        case SIGCONT:
            //Continued, means stopped
            break;
        case SIGUSR1:
            //Resetting Net Responsibility
            _instance->uninitialize();
            _instance->initialize(*_instance);
            break;
        case SIGUSR2:
            //Other action or just mask it
            break;
        default:
            //Caught signal
            break;
    }
#endif
}



bool MainApplication::isHalting() {
#if defined(POCO_OS_FAMILY_UNIX)
    string cmd("runlevel");
    vector<string> args;
    Poco::Pipe outPipe;
    ProcessHandle ph = Process::launch(cmd, args, 0, &outPipe, 0);
    ph.wait();
    Poco::PipeInputStream istr(outPipe);
    stringstream ss;
    Poco::StreamCopier::copyStream(istr, ss);
    int runlevel;
    ss.seekg(-2, ios::end);
    ss >> runlevel;
    return (runlevel == 0 || runlevel == 1 || runlevel == 6);
#else
    return false;
#endif
}

【问题讨论】:

  • 为什么你的服务被SIGTERM 终止并且整个系统被关闭时会有不同的行为?
  • 它在于程序的概念。它旨在始终运行。但是,如果应该关闭它,则必须将其报告给特定的电子邮件地址。我不希望计算机启动和重新启动的所有时间的统计信息,但我希望确定用户是否手动中断了它。希望这有点道理:)
  • 系统管理员必须例如在他的服务器上升级您的程序(或停止您正在使用的数据库!)可能对“打算始终运行”有不同的看法。所以让他管理他的系统的能力......
  • 我知道这听起来像是某种恶意软件,但它是accountability software。因此,如果系统管理员不希望它运行,他将永远不会安装它。这个概念几乎是“我不相信自己的浏览习惯,所以我想负责”。如果这样的程序没有注意到 SIGTERM,它将毫无用处。
  • @roggan87:我的暗示是你需要重新考虑你的方法。在普通的“kill”失败后尝试“kill -9”并不像你需要成为黑客天才。

标签: c++ linux signals halt runlevel


【解决方案1】:

我最终选择了另一条路线来解决这个问题。现在我正在读取计算机的启动历史并将其与软件的历史进行比较,以查看计算机是否在没有软件的情况下启动或停止。这已经足够了,而且可能会更准确。

Linux中用来判断启动历史的命令是

$ last reboot

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 2018-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多