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

QProcess freezes UI



  • Hello,

    I'm using a QProcess to run system commands but it freezes the UI while using waitForFinished which is normal as its indicated in the documentation. I tried to use signals and slots but it still freezes. Here is my code:

    bool NetworkConnection::connectEthernetDynamic(){
    
     
        QProcess con_process = new QProcess;
        
        con_process->start("nmcli con add type ethernet con-name my_connection ifname eth0");
        connect(con_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                [this, con_process](int exitCode, QProcess::ExitStatus exitStatus){
            QString output2(con_process->readAllStandardOutput());
            if (output2.contains("successfully")){
                QProcess process;
                process.start("nmcli con up my_connection");
                process.waitForFinished();
                QString output3(process.readAllStandardOutput());
                return output3.contains("successfully");
            }
        });
    }
    
    

  • Lifetime Qt Champion

    Hi,

    Signals and slots does not mean that the slot is executed in a different thread. The only time it is the case is when the target thread affinity is a different thread than the one where the signal is originating.



  • @Iheb
    What can we say other than: your outer QProcess does not use waitForFinished(), so it does not block. But if you get successfully back, you then create another QProcess which does call waitForFinished(). Hence that blocks.

    I tried to use signals and slots but it still freezes.

    Show what you did, because signals & slots will not block/freeze. One way would be: if you make your inner process do a signal on QProcess::finished just like you outer one does, that would be a starting approach.



  • @SGaist Hi, so what should I do?



  • @Iheb said in QProcess freezes UI:

    @SGaist Hi, so what should I do?

    @JonB said in QProcess freezes UI:

    One way would be: if you make your inner process do a signal on QProcess::finished just like you outer one does, that would be a starting approach.

    Did you choose to ignore this suggestion? Or do you only wish @SGaist to respond?



  • @JonB Yes I thought about that too and I tried something like this but it still freezes

    bool NetworkConnection::connectEthernetDynamic(){
         auto con_process = new QProcess;
         con_process->start("nmcli con add type ethernet con-name my_connection ifname eth0");
         connect(con_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                     [this, con_process](int exitCode, QProcess::ExitStatus exitStatus){
                 QString output2(con_process->readAllStandardOutput());
                 if (output2.contains("successfully")){
                    auto process = new QProcess;
                    process->start("nmcli con up my_connection");
                    connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                            [this, process](int exitCode, QProcess::ExitStatus exitStatus){
                                QString output3(process->readAllStandardOutput());
                                return output3.contains("successfully");
                    });
                }
            });
    }
    
    


  • @Iheb
    Looking through, I would not expect this to "freeze", whatever else it might do. Put it some qDebug() statements, immediately before & after the start() lines and at each step in the slots. You/we need to understand what line you say it blocks/freezes on in the code you show.

    EDIT Oohh, I just noticed: you are connecting your slots after you have issued the start() statement. You must not do that, it may (well) be missed! connect() the signal/slot immediately after creating the QProcess instances, before you go start() on them.

    As a separate observation, once you have this working satisfactorily you will need to delete the two QProcesses you create which currently leak.



  • @JonB I didn't choose to ignore your suggestion nor wishing only @SGaist to reply I simply just have about 10 min 1-reply interval (I don't have enough reputation to reply so I have to wait 10 min between each one)



  • @Iheb said in QProcess freezes UI:

    @JonB I didn't choose to ignore your suggestion nor wishing only @SGaist to reply I simply just have about 10 min 1-reply interval (I don't have enough reputation to reply so I have to wait 10 min between each one)

    Not a problem :) Read my latest response above, including the need to change the order of your statements, and let us know.



  • @Iheb
    And a further observation, which might affect how you are (trying to) use this code.

    The return output3.contains("successfully") statement only returns a result for the slot connected to the second QProcess --- which is thrown away, as nobody cares about it.

    Meanwhile you have bool NetworkConnection::connectEthernetDynamic(), which at present is not returning any result itself. I am surprised you do not get a compiler warning for this? You must arrange your code differently, your connectEthernetDynamic() is non-blocking (as you desire) so it cannot return a value about the completion of the processes. Instead it will return immediately. So if you need to use the second process's output result, you will need to change how you do that. But you should be able to get the processes running without freeze initially if you skip needing the result.


  • Lifetime Qt Champion

    @Iheb said in QProcess freezes UI:

    @SGaist Hi, so what should I do?

    As @JonB suggests, rethink your design to properly take advantage of the asynchronous nature of Qt.



  • @JonB Hi again, I confirm your suggestion works well. I found that I have another QProcess running just before the function and has waitforfinished. Using nested signal and slots for QProcess won't freeze the UI. I also managed to arrange my code to work as desired and the connectEthernetDynamic() became a void function.



  • @Iheb Could you share your new working code please?


Log in to reply