从 Unix 信号处理器调用 Qt 函数
您不能从 Unix 信号处理器中调用 Qt 函数。标准的 POSIX 规则适用:您只能从信号处理器调用异步信号安全函数。有关可从 Unix 信号处理程序调用的函数的完整列表,请参阅信号操作。
但不要绝望,有一种方法可以在 Qt 中使用 Unix 信号处理程序。策略是让你的 Unix 信号处理程序做一些最终会导致 Qt 信号发出的事情,然后你只需从 Unix 信号处理程序返回即可。在 Qt 程序中,该 Qt 信号被发出,然后被 Qt 槽函数接收,在那里,你可以安全地执行 Unix 信号处理程序中不允许执行的任何 Qt 操作。
实现这一点的一个简单方法是在你的类中为你要处理的每个 Unix 信号声明一个套接字对。套接字对声明为静态数据成员。您还可以创建一个QSocketNotifier 来监控每个套接字对的读取端,将 Unix 信号处理程序声明为静态类方法,并声明一个与每个 Unix 信号处理程序相对应的槽函数。在本例中,我们打算同时处理 SIGHUP 和 SIGTERM 信号。注意:在阅读下面的代码片段之前,请先阅读 socketpair(2) 和 sigaction(2) 的手册。
class MyDaemon : public QObject { Q_OBJECT public: MyDaemon(QObject *parent = 0); ~MyDaemon(); // Unix signal handlers. static void hupSignalHandler(int unused); static void termSignalHandler(int unused); public slots: // Qt signal handlers. void handleSigHup(); void handleSigTerm(); private: static int sighupFd[2]; static int sigtermFd[2]; QSocketNotifier *snHup; QSocketNotifier *snTerm; };
在 MyDaemon 构造函数中,使用 socketpair(2) 函数初始化每一对文件描述符,然后创建QSocketNotifier 以监控每一对文件描述符的读取端。每个QSocketNotifier 的 activated() 信号都会连接到相应的槽函数,从而有效地将 Unix 信号转换为 QSocketNotifier::activated() 信号。
MyDaemon::MyDaemon(QObject*parent) : QObject(parent) {if(::socketpair(AF_UNIX,SOCK_STREAM, 0,sighupFd)) qFatal("Couldn't create HUP socketpair"); 如果(::socketpair(AF_UNIX,SOCK_STREAM, 0,sigtermFd)) qFatal("Couldn't create TERM socketpair"); snHup= newQSocketNotifier(sighupFd[1]、 QSocketNotifier::读取, this); connect(snHup, &QSocketNotifier::激活, this, &MyDaemon::handleSigHup); snTerm= newQSocketNotifier(sigtermFd[1]、 QSocketNotifier::读取, this); connect(snTerm, &QSocketNotifier::activated, this, &MyDaemon::handleSigTerm); ...}
在实现文件中初始化静态成员:
int MyDaemon::sighupFd[2] = {0, 0}; int MyDaemon::sigtermFd[2] = {0, 0};
在启动代码的其他地方,使用 sigaction(2) 安装 Unix 信号处理器。
static int setup_unix_signal_handlers() { struct sigaction hup, term; hup.sa_handler = MyDaemon::hupSignalHandler; sigemptyset(&hup.sa_mask); hup.sa_flags = 0; hup.sa_flags |= SA_RESTART; if (sigaction(SIGHUP, &hup, 0)) return 1; term.sa_handler = MyDaemon::termSignalHandler; sigemptyset(&term.sa_mask); term.sa_flags = 0; term.sa_flags |= SA_RESTART; if (sigaction(SIGTERM, &term, 0)) return 2; return 0; }
在您的 Unix 信号处理器中,您将向套接字对的写入端写入一个字节并返回。这将导致相应的QSocketNotifier 发出激活()信号,进而导致相应的 Qt XML 插槽函数运行。
void MyDaemon::hupSignalHandler(int) { char a = 1; ::write(sighupFd[0], &a, sizeof(a)); } void MyDaemon::termSignalHandler(int) { char a = 1; ::write(sigtermFd[0], &a, sizeof(a)); }
在连接到 QSocketNotifier::activated() 信号的槽函数中,您将读取字节。现在你带着信号安全地回到了 Qt 中,可以做所有在 Unix 信号处理器中不允许做的 Qt 事情了。
void MyDaemon::handleSigTerm() { snTerm->setEnabled(false); char tmp; ::read(sigtermFd[1], &tmp, sizeof(tmp)); // do Qt stuff snTerm->setEnabled(true); } void MyDaemon::handleSigHup() { snHup->setEnabled(false); char tmp; ::read(sighupFd[1], &tmp, sizeof(tmp)); // do Qt stuff snHup->setEnabled(true); }
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.