유닉스 시그널 핸들러에서 Qt 함수 호출하기

Unix 시그널 핸들러에서는 Qt 함수를 호출할 수 없습니다. 표준 POSIX 규칙이 적용됩니다: 시그널 핸들러에서는 비동기 신호 안전 함수만 호출할 수 있습니다. Unix 시그널 핸들러에서 호출할 수 있는 전체 함수 목록은 시그널 액션을 참조하십시오.

하지만 절망하지 마세요. Qt와 함께 유닉스 시그널 핸들러를 사용할 수 있는 방법이 있습니다. 이 전략은 Unix 시그널 핸들러가 결국 Qt 시그널을 발생시키는 작업을 수행하도록 한 다음, Unix 시그널 핸들러에서 간단히 복귀하는 것입니다. Qt 프로그램으로 돌아가면 해당 Qt 신호가 방출된 다음 Qt 슬롯 함수에 의해 수신되고, 여기서 유닉스 시그널 핸들러에서 허용되지 않았던 모든 Qt 작업을 안전하게 수행할 수 있습니다.

이를 실현하는 간단한 방법 중 하나는 처리하려는 각 Unix 신호에 대해 클래스에서 소켓 쌍을 선언하는 것입니다. 소켓 쌍은 정적 데이터 멤버로 선언됩니다. 또한 QSocketNotifier 을 생성하여 각 소켓 쌍의 읽기 끝을 모니터링하고, Unix 신호 처리기를 정적 클래스 메서드로 선언한 다음, 각 Unix 신호 처리기에 해당하는 슬롯 함수를 선언합니다. 이 예제에서는 SIGHUP 및 SIGTERM 신호를 모두 처리하려고 합니다. 참고: 다음 코드 조각을 살펴보기 전에 소켓페어(2) 및 시그액션(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 생성자에서 소켓페어(2) 함수를 사용하여 각 파일 설명자 쌍을 초기화한 다음 QSocketNotifier 을 생성하여 각 쌍의 읽기 끝을 모니터링합니다. 각 QSocketNotifier 의 활성화() 신호는 적절한 슬롯 함수에 연결되며, 이 함수는 유닉스 신호를 QSocketNotifier::활성화() 신호로 효과적으로 변환합니다.

MyDaemon::MyDaemon(QObject *부모) : QObject(부모) { 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;
}

유닉스 시그널 핸들러에서는 소켓 쌍의 쓰기 끝에 바이트를 쓰고 반환합니다. 그러면 해당 QSocketNotifier 에서 활성화() 신호가 발생하고, 적절한 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로 안전하게 돌아왔으며, 유닉스 시그널 핸들러에서 할 수 없었던 모든 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.