Как закрыть дочерний процесс Qt и заставить дочерний процесс выполнить код очистки? - PullRequest
2 голосов
/ 21 сентября 2011

Я запускаю процесс в Linux / Qt, а затем запускаю некоторые дочерние процессы, используя QProcess. Затем, в конце концов, я хочу изящно закрыть дочерние процессы (или выполнить некоторый код очистки).

Дочерние процессы используют QSharedMemory , и сейчас, когда я вызываю QProcess :: close (), дочерние процессы закрываются без вызова QSharedMemory :: detach () , и результат что все процессы закрыты ... но осталась общая память, которая не очищена.

У меня есть код для дочернего процесса, и в коде есть функция cleanup(). Как родительский процесс закрывает QProcess таким образом, чтобы дочерний процесс выполнял cleanup()?

Ответы [ 3 ]

2 голосов
/ 21 сентября 2011

Я заставил ребенка выполнить код очистки Qt с помощью обработчиков сигналов unix.

Вот объяснение высокого уровня:

  • родитель открывает дочерний процесс, используя QProcess
  • обработка происходит
  • родитель закрывает дочерний процесс, используя QProcess :: terminate (), который вызывает сигнал SIGTERM для дочернего процесса
  • ребенок реализует обработчик сигнала Unix для SIGTERM
  • из обработчика сигнала unix qApp-> exit (0); происходит
  • qApp испускает сигнал Qt "aboutToQuit ()"
  • подключить слот дочернего процесса cleanup () к сигналу qApp aboutToQuit ()

Дочерний код процесса для обработки unix-сигнала SIGTERM:

static void unixSignalHandler(int signum) {
    qDebug("DBG: main.cpp::unixSignalHandler(). signal = %s\n", strsignal(signum));

    /*
     * Make sure your Qt application gracefully quits.
     * NOTE - purpose for calling qApp->exit(0):
     *      1. Forces the Qt framework's "main event loop `qApp->exec()`" to quit looping.
     *      2. Also emits the QCoreApplication::aboutToQuit() signal. This signal is used for cleanup code.
     */
    qApp->exit(0);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MAINOBJECT mainobject;

    /*
     * Setup UNIX signal handlers for some of the common signals.
     * NOTE common signals:
     *      SIGINT:     The user started the process on the command line and user ctrl-C.
     *      SIGTERM:    The user kills the process using the `kill` command.
     *                  OR
     *                  The process is started using QProcess and SIGTERM is
     *                  issued when QProcess::close() is used to close the process.
     */
    if (signal(SIGINT, unixSignalHandler) == SIG_ERR) {
        qFatal("ERR - %s(%d): An error occurred while setting a signal handler.\n", __FILE__,__LINE__);
    }
    if (signal(SIGTERM, unixSignalHandler) == SIG_ERR) {
        qFatal("ERR - %s(%d): An error occurred while setting a signal handler.\n", __FILE__,__LINE__);
    }
    // executes mainbobject.cleanupSlot() when the Qt framework emits aboutToQuit() signal.
    QObject::connect(qApp,          SIGNAL(aboutToQuit()),
                     &mainobject,   SLOT(cleanupSlot()));

    return a.exec();
}

Вывод:

I подтвердил, что это решение работает .

Я думаю, что это хорошее решение, потому что:

  • позвольте родителю закрыть дочерний процесс таким образом, чтобы дочерний процесс выполнил очистку
  • если родительский объект по ошибке закрывается и оставляет дочерний процесс запущенным, пользователь / sysadmin может уничтожить оставшийся дочерний процесс с помощью команды kill, и дочерний процесс все равно очистится после себя перед закрытием

p.s. «Почему бы просто не выполнить код очистки непосредственно в точке входа обработчика сигналов?»

Краткий ответ: вы не можете. Вот объяснение того, почему вы не можете выполнить свой код очистки Qt в функции обработчика сигналов unix. Из документации Qt "Вызов функций Qt из обработчиков сигналов Unix" :

Вы не можете вызывать функции Qt из обработчиков сигналов Unix. Стандарт Применяется правило POSIX: Вы можете вызывать асинхронно-безопасные функции только из обработчики сигналов. См. Сигнальные действия для полного списка функций. Вы можете звонить из обработчиков сигналов Unix.

0 голосов
/ 21 сентября 2011

Я считаю, что вам нужно реализовать небольшой протокол здесь.Вам нужен способ сообщить дочернему процессу о том, чтобы выйти изящно.Если у вас есть источник для обоих, вы можете попытаться реализовать такой сигнал, используя библиотеку QtDBus.

0 голосов
/ 21 сентября 2011

Вы можете попробовать подключить сигнал processExited () к слоту, чтобы самостоятельно отсоединяться от разделяемой памяти, насколько я знаю, в QProcess нет ничего, что напрямую вызывало бы метод отсоединения.

...