确定 c++ 中的系统停止
好吧,我正在开发一个用 C++ 编写的程序,该程序作为守护进程运行。它主要针对 Linux 用户,但我希望也包括 Windows(作为服务运行)和 Mac 用户。
我希望守护进程在手动关闭时进行记录。但是,它不应该不记录由于系统停止或重新启动而导致的系统关闭。
目前我已经屏蔽了所有信号并使用 sigaction() 实现了某种处理。在记录关闭之前,还有一个函数会检查系统的运行级别,如果是 0, 1 0r 6 则忽略记录。检查运行级别的方法是运行命令“runlevel”并处理输出。
我的问题是运行级别并不总是我所期望的。我正在运行 Ubuntu,当像往常一样登录时,我处于运行级别 2,重新启动时也是如此。当停止时,我有时从“运行级别”得不到任何输出。不同的 Linux 发行版使用自己的运行级别,因此它对于可移植性来说并不是最佳的。
那么有没有更好的方法来判断系统是否停止呢?另外,是否有更好的方法来捕获中断,例如通过异常处理等?
如果这里有任何帮助,我将粘贴一段代码。用 C++ 编写,使用 Poco C++ 库。
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
}
Alright so I'm working on a program written in c++ that is running as a daemon. It is primarily aiming Linux users, but I wish to include Windows (running as service) and Mac users as well.
I want the daemon to log whenever it is manually shut down. However it should not log shutdowns made by the system because of system halt or reboot.
Currently I've masked all signals and implemented some sort of handling using sigaction(). Before logging the shutdown, a function is also checking the system's runlevel, and if it is 0, 1 0r 6 the logging is omitted. The way to check the runlevel is to run the command "runlevel" and process the output.
My problem is that the runlevel is not always what I would expect it to. I'm running Ubuntu, and when logged in as usual I'm in runlevel 2, and that's the same when rebooting. When halting I sometimes get nothing as output from "runlevel". Different Linux distros are using their own runlevels, so it's not optimal for portability.
So is there a better way to determine if the system is halting? Also, is there a better way to catch interruptions, e.g. through exception handling etc?
I'll paste a snippet of the code, if it is of any help here. Written in c++, using the 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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我最终选择了另一条路线来解决这个问题。现在,我正在读取计算机的启动历史记录,并将其与软件的历史记录进行比较,以查看计算机是否在没有该软件的情况下启动或停止。这就足够了,而且可能会更加准确。
用于确定 Linux 中启动历史记录的命令是
I ended up going another route to solve the issue. Now I'm reading the computer's boot history and compares it to the history of the software to see if the computer booted or halted without the software. That's enough and will probably be even more accurate.
The command used to determine the boot history in Linux is