QT处理Unix信号

从Unix信号处理程序中调用Qt函数

你不能从Unix信号处理程序中调用Qt函数。适用于标准POSIX规则:只能从信号处理程序调用异步信号安全的函数。有关可以从Unix信号处理程序调用的函数的完整列表,请参阅Signal Actions

但不要绝望,有一种方法可以在Qt中使用Unix信号处理程序。策略是让Unix信号处理程序做一些事情,最终导致Qt信号被发出,然后您只需从Unix信号处理程序返回。回到你的Qt程序,Qt信号被发射,然后被Qt插槽函数接收,在这里你可以安全地做任何Qt的事情你在Unix信号处理程序中不允许做的事情。

一种简单的方法是**在类中为要处理的每个Unix信号声明一个套接字对。套接字对被声明为静态数据成员。还创建了一个QSocketNotifier来监视每个套接字对的读取结束,将Unix信号处理程序声明为静态类方法,并声明对应于每个Unix信号处理程序的插槽函数。**在这个例子中,我们打算同时处理SIGHUP和SIGTERM信号。注意:在阅读下面的代码片段之前,你应该先阅读socketpair(2)和sigaction(2)手册页。

cpp 复制代码
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()信号。

cpp 复制代码
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信号处理程序。

cpp 复制代码
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槽函数运行。

cpp 复制代码
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));
}

在连接到qsocketnotification::activated()信号的槽位函数中,读取字节。现在你安全地回到了Qt中,你的信号,你可以做所有Qt的东西,你不被允许做在Unix信号处理程序。

cpp 复制代码
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);
}
相关推荐
苕皮蓝牙土豆4 小时前
Qt 分裂布局:QSplitter 使用指南
开发语言·qt
m0_7202450112 小时前
QT(四)基本组件
数据库·qt·microsoft
IOT-Power13 小时前
Qt项目中使用 FieldManager 实现多进程间的字段数据管理
开发语言·qt·命令模式
小徐不徐说21 小时前
深入理解 Qt 信号与槽机制的底层逻辑
数据库·c++·qt·面试
大梦谁先行21 小时前
Qt写游戏脚本/辅助(仅供参考)
c++·qt·游戏
一只小小汤圆1 天前
qt 心跳包
服务器·数据库·qt
神仙别闹2 天前
基于QT(C++)实现(图形界面)选课管理系统
java·c++·qt
「QT(C++)开发工程师」2 天前
Qt C++动态库SDK在Visual Studio 2022使用(C++/C#版本)
c++·qt·c#·visual studio
程序员编程指南2 天前
Qt 与 WebService 交互开发
c语言·开发语言·c++·qt·交互
溟洵2 天前
Qt 窗口 工具栏QToolBar、状态栏StatusBar
开发语言·前端·数据库·c++·后端·qt