从 Unix 信号处理器中调用 Qt 函数
您不能从 Unix 信号处理器中调用 Qt 函数。标准 POSIX 规则适用:您只能从信号处理器中调用异步信号安全的函数。有关可以从 Unix 信号处理器中调用的函数完整列表,请参阅信号操作。
但不要气馁,有一种方法可以与 Qt 一起使用 Unix 信号处理器。策略是让您的 Unix 信号处理器执行某些操作,这些操作最终会导致 Qt 信号被发射,然后您只需从中返回 Unix 信号处理器。在您的 Qt 程序中,该 Qt 信号被发射,然后被您的 Qt 槽函数接收。在 Qt 信号处理器中,您可以安全地执行您不允许在 Unix 信号处理器中做的任何 Qt 相关操作。
实现这一点的简单方法是为每个要处理的 Unix 信号在您的类中声明一个套接字对。套接字对被声明为静态数据成员。您还为每个套接字对的读取端创建一个QSocketNotifier 进行监控,将您的 Unix 信号处理器声明为静态类方法,并为每个 Unix 信号处理器声明一个对应的槽函数。在此示例中,我们旨在处理 SIGHUP 和 SIGTERM 信号。注意:在深入以下代码片段之前,您应该阅读 socketpair(2) 和 sigaction(2) 的 man 页面。
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"); if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd)) qFatal("Couldn't create TERM socketpair"); snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this); connect(snHup, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigHup())); snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this); connect(snTerm, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigTerm())); ... }
在您的启动代码的另一个地方,您使用 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 发射其 activated() 信号,然后这将导致适当的 Qt 槽函数运行。
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); }
© 2024 Qt 公司有限公司。文档贡献的版权归其各自的拥有者。此处提供的文档采用自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款进行许可。Qt 及其相应的标志是芬兰和/或世界其他地区的 The Qt Company Ltd. 的商标。所有其他商标均为其各自所有者的财产。