Solved QProcess start() freezes GUI with QEventLoop
-
Hi,
I'm running a GUI in HTML with QWebEngine and QWebChannel on Embedded Linux. Everything works fine except at some point when I try to run commands with QProcess. The GUI freezes.
Here is the code causing the GUI to freeze:
bool enableGsm(bool enable) { QProcess process; QStringList cmd; QEventLoop loop; connect(&process, SIGNAL(finished(int)), &loop, SLOT(quit())); cmd << "gsm" << "set_conf" << "enable" << (enable ? "true" : "false"); process.start(cmd.join(' ')); loop.exec(); if (QString(process.readAllStandardOutput()).contains("OK")) { cmd.clear(); cmd << "ifup" << (enable ? GSM_INTERFACE : WLAN_INTERFACE); process.start(cmd.join(' ')); loop.exec(); auto info = qInfo(); info.noquote(); info << "GSM " << (enable ? "enabled" : "disabled") << "."; return true; } return false; }
I make this function invokable:
Q_INVOKABLE bool enableGsm(bool enable);
And run it from JavaScript:
conf.enableGsm(enable);
The
ifup
command can be pretty long to run so the GUI freezes for a long time and goes back OK once finished. In other similar cases with aping
command it doesn't freeze. -
@cyrilfr You're blocking your UI with that event loop not QProcess. Why do you have that event loop?
You can connect a slot to finished() signal from your QProcess to get notified when it is finished. -
OK, I thought the purpose of QEventLoop was to avoid GUI freeze. I'll try to connect to a JS slot otherwise. Thanks.
-
@jsulm I tried using a slot connected to the readyReadStandardOutput signal but it says:
{WARNING} QProcess: Destroyed while process ("ifup") is still running.
At the end of the function.
void enableGsm(bool enable) { QProcess process; QStringList cmd; cmd << "gsm" << "set_conf" << "enable" << (enable ? "true" : "false"); process.start(cmd.join(' ')); process.waitForFinished(); if (QString(process.readAllStandardOutput()).contains("OK")) { cmd.clear(); cmd << "ifup" << (enable ? GSM_INTERFACE : WLAN_INTERFACE); connect(&process, &QProcess::readyReadStandardOutput, [this, enable] { auto info = qInfo(); info.noquote(); info << "GSM " << (enable ? "enabled" : "disabled") << "."; emit gsmConfigured(true); }); process.start(cmd.join(' ')); } else { emit gsmConfigured(false); } }
-
@cyrilfr Currently you're allocating QProcess instance on the stack inside your method - it is destroyed as soon as the method finishes. Simply make the QProcess instance member of your class or allocate it on the heap (and delete later when not needed).
Also, now you're blocking again your UI because you callprocess.waitForFinished();
!
You should learn how asynchronous programming works, else you will struggle a lot with Qt and other assynchronous frameworks. Basically you have to move everything after process.start(cmd.join(' ')); to your finished() slot. -
@jsulm Putting the QProcess as a member resolved my issue. I know about waitForFinished() but in this case the command is short enough to run so it doesn't freeze at all.
Basically you have to move everything after process.start(cmd.join(' ')); to your finished() slot.
This is what I've done I guess.