Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Parent process, child process and QCoreApplication



  • I launch a child process with:

    QProcess* clsScriptHelper::pLaunch(QString strApp, QStringList& slstArgs) {
        QString strFullPath(clsDebugService::strGetUserFolder(strApp));
        qdbg() << "Checking for PID for: " << strFullPath;
        QProcess* pModule = nullptr;
        qint64 int64PID;
        if ( blnGetPID(strFullPath, int64PID) == true ) {
        //Process already running, no action required
        } else {
            int intLastSep = strFullPath.lastIndexOf(QDir::separator());
            qdbg() << "Process is NOT running, launching";
    
            if ( intLastSep > 0 ) {
                QString strName = strFullPath.mid(intLastSep + 1)
                       ,strPath = strFullPath.mid(0, intLastSep + 1);
                pModule = new QProcess();
                pModule->setArguments(slstArgs);
                pModule->setWorkingDirectory(strPath);
                pModule->setProgram(strName);
                pModule->start();
                int64PID = pModule->processId();
    
                if ( int64PID == 0 ) {
                    delete pModule;
                    pModule = nullptr;
                }
            }
        }
        if ( int64PID > 0 ) {
            qdbg() << "Process: " << strFullPath << " started, PID: " << QString::number(int64PID);
        }
        return pModule;
    }
    

    According to the documentation, using start will cause the child process to close when the parent is closed, which is exactly the functionality I want. It did work then I think after I modified the child to use QCoreApplication it has stopped working, in that when the parent process is terminated, the child process keeps running.

    Is there anything I can do to resolve this? I need the functionality of QCoreApplication.


  • Moderators

    @SPlatten
    you could connect to the aboutToQuit signal of QCoreApplication and call terminate or kill on your QProcess


  • Moderators

    @SPlatten
    you could connect to the aboutToQuit signal of QCoreApplication and call terminate or kill on your QProcess



  • @J-Hilk , Thank you, I literally just found the same on Google, implementing now.



  • @J-Hilk , I've implemented this:

     QObject::connect(pParent, SIGNAL(aboutToQuit()), this, SLOT(onExitModule()));
    

    And my slot:

    void clsModHelper::onExitModule() {
    #ifdef DEBUG_LOG
        if ( mfpDbgLog != nullptr ) {
            fclose(mfpDbgLog);
        }
    #endif        
        terminate();
    }
    

    However when the parent terminates the child process doesn't.


  • Moderators

    @SPlatten said in Parent process, child process and QCoreApplication:

    connect

    you should check the return value of that connect, AFAIK aboutToQuit is a signal of QCoreApplication only and I don't know what pParent is



  • @J-Hilk In the case where I am using it pParent is passed into the constructor and is the address of the core application:

    QCoreApplication a(intArgc, parystrArgv);
    QCoreApplication::setApplicationName(clsModFileIO::scpszTitle());
    clsModFileIO obj(&a, intArgc, parystrArgv);
    

    Constructor:

    clsModHelper::clsModHelper(QObject* pParent, int intArgc, char* parystrArgv[]
                              ,const char* cpszTitle, double dblVersion)
                : QTcpSocket(pParent)            
                , mdblVersion(dblVersion)
                , mfpDbgLog(nullptr)
                , mint64AppPID(QCoreApplication::applicationPid())
                , mstrTitle(cpszTitle)
                , muint16ModulePort(0), muint16LauncherPID(0)
                , muint16XMLMPAMport(0) {
        if ( intArgc < CLA_LAUNCHER_PID ) {
            std::cout << "Insufficient arguments, aborting!" << std::endl;
            exit(EXIT_FAILURE);
        }
        if ( mspThis == nullptr ) {
            mspThis = this;
        }
        muint16XMLMPAMport = (quint16)atoi(parystrArgv[CLA_XMLMPAM_PORT]);
        muint16ModulePort = (quint16)atoi(parystrArgv[CLA_MODULE_PORT]);
        muint16LauncherPID = (quint16)atoi(parystrArgv[CLA_LAUNCHER_PID]);
        setSocketOption(QAbstractSocket::LowDelayOption, 1);
        //Connect up the signals
        QObject::connect(pParent, SIGNAL(aboutToQuit()), this, SLOT(onExitModule()));
    ...
    

  • Moderators

    @SPlatten Well, yes

    but you pass on a QObject* and try to connect to a signal that a derived class has. That doesn't work out of the box.

    Thats why I said you should check the return value of QObject::connect its false in this case.
    And the "new" syntax would not compile.

    anyway,
    either qobject_cast pParent to QCoreApllication or use the singleton getter function qApp or equivalently QCoreApplication::instance()



  • @J-Hilk , I've just changed the code to:

        QCoreApplication* pCore = static_cast<QCoreApplication*>(pParent);
        QObject::connect(pCore, SIGNAL(aboutToClose()), this, SLOT(onExitModule()));
    

    Has the signal been renamed because I didn't see aboutToQuit, only aboutToClose?


  • Moderators



  • Using:

    QCoreApplication* pCore = static_cast<QCoreApplication*>(pParent);
    QObject::connect(pCore, SIGNAL(aboutToQuit), this, SLOT(onExitModule()));
    

    and the slot:

    void clsModHelper::onExitModule() {
    #ifdef DEBUG_LOG
        if ( mfpDbgLog != nullptr ) {
            fclose(mfpDbgLog);
        }
    #endif
        terminate();
    }
    

    I just can't get it to work. The child process stays running.



  • @SPlatten said in Parent process, child process and QCoreApplication:

    Has the signal been renamed because I didn't see aboutToQuit, only aboutToClose?

    To avoid this kind of error, use new connect syntax. So signals/slots validity will be checked at compilation time!

    //QCoreApplication* pCore = static_cast<QCoreApplication*>(pParent);
    auto pCore = qobject_cast<QCoreApplication*>(pParent);
    //QObject::connect(pCore, SIGNAL(aboutToClose()), this, SLOT(onExitModule()));
    QObject::connect(pCore, &QCoreApplication::aboutToQuit, this, &clsModHelper::onExitModule);
    


  • @SPlatten said in Parent process, child process and QCoreApplication:

    I just can't get it to work. The child process stays running.

    What is pParent? Why do you not use pApp or QCoreApplication::instance()?

    QObject::connect(pApp, &QCoreApplication::aboutToQuit, this, &clsModHelper::onExitModule);
    


  • @KroMignon , because I didn't know it was there, just changed code to:

    QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit
                    ,this, &clsModHelper::onExitModule);
    

    Still doesn't work.


  • Lifetime Qt Champion

    @SPlatten said in Parent process, child process and QCoreApplication:

    Still doesn't work

    So, did you actually check whether the onExitModule slot was called?



  • @SPlatten said in Parent process, child process and QCoreApplication:

    Still doesn't work.

    What does not work?
    The slot is not called or the instance does not stop?



  • @jsulm , yes and it isn't.


  • Moderators

    @SPlatten than I would assume your application doesn't actually quit :P

    call quit manually in a timer after x amount of seconds, to see if everything closes correctly



  • @SPlatten said in Parent process, child process and QCoreApplication:

    According to the documentation, using start will cause the child process to close when the parent is closed, which is exactly the functionality I want. It did work then I think after I modified the child to use QCoreApplication it has stopped working, in that when the parent process is terminated, the child process keeps running.

    I'm going to throw my 2 cents in. Child process exiting when parent process exits --- so long as not detached, and child does not do something in its start up code to prevent it --- is an OS thing, not a Qt/C++ thing. So I would expect it to exit when parent exits, regardless of QCoreApplication or otherwise.[*]

    Are you sure (I mean 100%, guaranteed, you'll stake your grandmother on it) your parent process is exiting? For example, if it doesn't have a UI you won't get the default "exit app on last window closed" behaviour....

    [*] EDIT I'm rethinking my claim/stance on this, OS-wise. It's more complex than I recalled. Luckily, I don't have any grandmother to stake on this statement, though I may be 2 cents poorer....



  • @JonB , It doesn't the process was launched using QProcess and the start method, I stopped the process that launched the child by closing all the windows. I then checked the processes running using:

    ps -A
    

    I can see the child is still running. I also attached to the child process using Qt Creator and put a break point in the onExitModule slot, it never gets there.



  • @SPlatten said in Parent process, child process and QCoreApplication:

    I stopped the process that launched the child by closing all the windows.

    I don't understand. You said it's now a QCoreApplication...

    Oh, it's the child which is the QCoreApplication, not the parent?

    I stopped the process that launched the child by closing all the windows

    Maybe. Nonetheless, verify that the parent really does exit? Verify its (the parent's) PID has gone?

    I am lost. Could you please make clear which process(es) are QCoreApplications and which are QApplications, out of your parent & children? Just simply & clearly.

    Now that I have withdrawn/reneged on my earlier post claiming that OS will terminate children on parent exit:

    If your parent is a UI application, you should be able to get its aboutToQuit(), and forcibly kill any child processes. Why you should need to do that when you used QProcess::start() I'm not sure.



  • @JonB To clarify, the child application main:

    int main(int intArgc, char* parystrArgv[]) {
        QCoreApplication a(intArgc, parystrArgv);
        QCoreApplication::setApplicationName(clsModFileIO::scpszTitle());
        clsModFileIO obj(&a, intArgc, parystrArgv);
        return a.exec();
    }
    

    The constructor for clsModFileIO:

    clsModHelper::clsModHelper(QObject* pParent, int intArgc, char* parystrArgv[]
                              ,const char* cpszTitle, double dblVersion)
                : QTcpSocket(pParent)            
                , mdblVersion(dblVersion)
                , mfpDbgLog(nullptr)
                , mint64AppPID(QCoreApplication::applicationPid())
                , mstrTitle(cpszTitle)
                , muint16ModulePort(0), muint16LauncherPID(0)
                , muint16XMLMPAMport(0) {
        if ( intArgc < CLA_LAUNCHER_PID ) {
            std::cout << "Insufficient arguments, aborting!" << std::endl;
            exit(EXIT_FAILURE);
        }
        if ( mspThis == nullptr ) {
            mspThis = this;
        }
        muint16XMLMPAMport = (quint16)atoi(parystrArgv[CLA_XMLMPAM_PORT]);
        muint16ModulePort = (quint16)atoi(parystrArgv[CLA_MODULE_PORT]);
        muint16LauncherPID = (quint16)atoi(parystrArgv[CLA_LAUNCHER_PID]);
        setSocketOption(QAbstractSocket::LowDelayOption, 1);
        //Connect up the signals
        QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit
                        ,this, &clsModHelper::onExitModule);
       ...
    


  • @SPlatten
    Your reply may have crossed with my update.

    • I can now see that your child processes are clearly QCoreApplication.

    • What is your parent application? QApplication or QCoreApplication?

    EDIT
    No, no, what's this:

        //Connect up the signals
        QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit
                        ,this, &clsModHelper::onExitModule);
    

    That is "about to quit" in the child. I thought you said you want to the parent to exit, and the children should exit at the same time, isn't that your whole question?



  • @JonB Parent application main:

    QApplication a(argc, argv);
    


  • @SPlatten
    Did you see my EDIT in previous post?



  • @JonB Thats in the child process, sorry, just read the whole edit. What I want is the child process to automatically close when the parent is terminated.



  • @SPlatten
    I can see your connect(aboutToQuit) is in the child process. That's the wrong place if you are saying:

    1. You have a parent process (UI QApplication).

    2. You have that spawn some child processes, via QProcess::start().

    3. You exit the parent (perhaps you close all its windows)...

    4. ... And you want the previously-spawned child processes to exit when the parent does.

    Can't you just say if that is what you are asking?

    EDIT Ah, OK, I think you have edited to say that is indeed what you want.

    OK then, you are putting the code in the wrong application :)

    Supposedly, you shouldn't have to do anything. QProcess::start() looks like it should do that, as a result of what it says for startDetached():

    If the calling process exits, the detached process will continue to run unaffected.

    I think you may have said at one point the children were exiting when the parent did. And then I think you say you happened to change the children to QCoreApplication, and, for whatever reason, they ceased exiting when the parent does?

    Anyway. If your children are not exiting and you want them to do so when exiting the parent, we are (at least I am) suggesting you forcibly terminate them from the parent just before it exits. So, in the parent, keep a list of the created, non-exited child QProcesses. Catch the aboutToQuit or whatever signal in the parent, make that QProcess::terminate() (or failing that QProcesss::kill()) the children just before exiting the parent.

    Is that what you need?

    Separately. IF your parent/children are server/clients across sockets to each other --- as I thought they were --- the server should be able to send a message and close the sockets to the clients, and they should exit on that, instead of terminating processes.


Log in to reply