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

Can't kill QProcess in overriden closeEvent()



  • Hello all,

    I'm facing troubles to close a program started with QProcess. The problem seems to be that I wan't to kill the process after I have pressed the exit button. So in other words I attempt to kill the process in overridden QcloseEvent function. the kill() command won't kill the process for some reason. I tested that kill() works fine, if I do it in another function before closing the GUI app.

    Could someone advice me how can I kil() the process properly when exiting the GUI? I'm newbie Qt and rather novice in C++ also.

    Here is my implementation of the app

    The ui header file where I override the QCloseEvent and initialize the Qprocess pointer

    class Ui_MainWindow :public QMainWindow
    {
    protected:
       void closeEvent (QCloseEvent *event) override;
    
    public:
        QWidget *centralwidget;
        QFrame *frame;
    ...
        QProcess *scanProcess;
    ...
    
    

    Here is the method where start the process:

    void Ui_MainWindow::start_scan(){
    
            std::cout << "rosrun point_collector collector " << scantime->text().toStdString() << " " << savepath->text().toStdString() << std::endl;
            QString str = "rosrun point_collector collector "+ scantime->text()+" "+savepath->text()+" "+"lidar/lidar"+" "+"lidar_frame"+" "+"worksite";
            scanProcess->setProcessChannelMode(QProcess::MergedChannels);
            scanProcess->start(str);
            bool started = scanProcess->waitForStarted(1000);
            std::cout << started << " Started" << std::endl;
    }
    

    And the closeEvent implementation:

    void Ui_MainWindow::closeEvent (QCloseEvent *event)
    {
       QMessageBox::StandardButton resBtn = QMessageBox::question( this,tr("box"),
                                    tr("Are you sure?\n"),
                    QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
                    QMessageBox::Yes);
    
        if (resBtn != QMessageBox::Yes) {
            event->ignore();
        }  
        else {
                std::cout << "Scan process running. will be killed" << std::endl;
                //scanProcess->terminate();
                //scanProcess->close();
                 scanProcess->kill();
                 event->accept();
        }
    }
    

    Thanks for tips in advance!



  • @nikko1991
    Don't know why kill() works in some places but not others. If you say it does work from other places I can't see why QMainWindow::closeEvent() would not work, it really should be fine/not be relevant from there. If it were me I would check again! And test with some command other than your rosrun.

    Just to verify, try replacing your event->accept(); with event->ignore();, does that somehow make it work?

    You could instead try the kill() in one of QCoreApplication::aboutToQuit() or QGuiApplication::lastWindowClosed(), but these will actually come later, I'd be surprised if they work when from closeEvent() does not....



  • Thanks for such a fast reply @JonB !

    I see now that the problem seem to be connected with ROS (rosrun). If I wait for too long (1-2 sec) Qprocess some how loses my rosnode and is not able to kill it anymore. Although it claims that the process is killed. By coding start() and kill() after another killing is sucesfull. Otherwise not..

    I tested this with gnome-calculator. I was able to kill and also terminate the calculator in the closeEvent() function. Or the class destructor killed it. Im not 100% sure, but I feel that somehow the class destruction of my UI_MainWindow may bypass my actions in the closeEvent(). Is this possible?

    Anyway, as I undestand my rosnode should also be killed in the class destructor where I delete the QProcess object. Even if would not kill() "manually"..

    So, I ques I need to move back for ROS forums..

    Tips and ideas are still welcome here too!
    Thanks
    Nikko



  • @nikko1991 said in Can't kill QProcess in overriden closeEvent():

    somehow the class destruction of my UI_MainWindow may bypass my actions in the closeEvent(). Is this possible?

    I don't know what this means. If, for whatever reason, your Ui_MainWindow::closeEvent() is not executed then the kill() you show there will not be called. If this is a problem, I suggested to you earlier that closeEvent() might not be the best place to be killing a subprocess and gave you a couple of alternatives. Or perhaps in a destructor, or back in main() where you exit from QApplication::exec(), might be better.

    Having said this, maybe the whole thing is not necessary. It's not terribly clear from the documentation, but assuming you are using QProcess:start() to run your subprocess it may be terminated on exiting your application anyway. Because unlike QProcess:start(), QProcess:startDetached() states

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

    which implies to me that they expect non-detached processes to be terminated. You would have to investigate.

    You will also have to investigate the behaviour of your rosrun executable. Applications can do various things to avoid/ignore certain kinds of killing.



  • Nevermind. I read this as threading related, not processes...apples and oranges.

    In general it is considered bad to kill() a thread, so many threading libraries don't have the option. A better approach is to set an event flag to tell the thread to exist gracefully and allow the thread to do its cleanup if necessary.



  • @JonB
    I tried to do killing trough QApplication::aboutToQuit() and QApplication::lastWindowClosed() signals. They did not work out.

    I also tried killing the process with various ways in my UI destructor without luck.

    Tried to kill this process with another QProcess.start("rosnode kill point_collector") that is one way of killing my node in ROS. No luck. "rosnode kill point_collector" works fine in terminal (in any directory) although I start the node with Qprocess in my UI.
    Also QProcess.start("kill -SIGINT " + QString::number(scanProcess->processId()) did not work out.

    @Kent-Dorfman
    Do I have other options than Qprocess.terminate() or QProcess.close() instead of kill()? I have tried those.

    I will keep investigating. Thanks for tips again.



  • @nikko1991
    That's all (terminate/close/kill) the options you have. QProcess::kill() really should be a normal kill. I'd try kill -9 rather than your kill -SIGINT. Running a QProcess.start("kill ... really is the same as doing it in a terminal. You'll have to try to figure what's going on: if these things work against a program other than rosrun then that is somehow the issue, which only you can play with.


  • Lifetime Qt Champion

    Hi,

    Since you are managing a ROS node, can you send a commande to shut it down properly rather than killing it ?



  • yes. if you are on a posix system then send the kill via a signal instead of invoking yet another process call.

    assuming you know the process pid then

    SYNOPSIS
           #include <sys/types.h>
           #include <signal.h>
    
           int kill(pid_t pid, int sig);
    
       Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
    
           kill(): _POSIX_C_SOURCE
    
    
    

    The concern would be that the qprocess kill makes that exact same call so if it isn't dieing using the native Qt call then something more sinister is going on.



  • @Kent-Dorfman said in Can't kill QProcess in overriden closeEvent():

    The concern would be that the qprocess kill makes that exact same call so if it isn't dieing using the native Qt call then something more sinister is going on.

    I concur!


Log in to reply