Вопрос

I am starting a process in Linux/Qt and then starting some child processes using QProcess. Then eventually I want to close the child processes gracefully (aka execute some clean up code).

The child processes are using QSharedMemory and right now when I call QProcess::close() the child processes are closing without calling QSharedMemory::detach() and the result is that all the processes are closed... but there is left over shared memory that is not cleaned up.

I have the code for the child process and in the code there is the function cleanup(). How does the parent process close the QProcess in such a manner so that the child process will execute cleanup()?

Это было полезно?

Решение

I got the child to execute Qt cleanup code using unix signal handlers.

Here's a high level explanation:

  • the parent opens the child process using QProcess
  • processing occurs
  • the parent closes the child process using QProcess::terminate() which raises the SIGTERM signal on the child
  • the child implements a unix signal handler for SIGTERM
  • from the unix signal handler the qApp->exit(0); occurs
  • qApp emits a Qt signal "aboutToQuit()"
  • connect the child process cleanup() slot to the qApp aboutToQuit() signal

Child process code to handle unix SIGTERM signal:

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();
}

Conclusion:

I confirmed that this solution works.

I think this is a good solution because:

  • let's the parent close the child process in such a way that the child process executes cleanup
  • if the parent closes mistakenly and leaves the child process running, the user/sysadmin can kill the leftover child process using kill command and the child process will still cleanup after itself before closing

p.s. "why not just do the cleanup code directly in the signal handler entry point?"

The short answer is because you can't. Here's an explanation as to why you can't execute your Qt cleanup code in the unix signal handler function. From Qt documentation "Calling Qt Functions From Unix Signal Handlers":

You can't call Qt functions from Unix signal handlers. The standard POSIX rule applies: You can only call async-signal-safe functions from signal handlers. See Signal Actions for the complete list of functions you can call from Unix signal handlers.

Другие советы

You could try connecting the processExited() signal to a slot to handle detaching from the shared memory yourself, as far as I'm aware there's nothing in QProcess that will directly trigger the detach method.

I believe you need to implement a small protocol here. You need a way to tell to the child process to exit gracefully. If you have the source for both, you may try to implement such a signal using QtDBus library.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top