0

I'm trying to understand why putting the a.exec() call in the following Qt 4.8 code does not need to happen before my QProcess waitForFinished() and waitForStarted() calls can work. I understand that a.exec() starts the event loop, and in my mind the waitFor* slots need to receive a signal ( i.e 'started()' or 'finished()' ) before moving on with execution. How can this happen if the event loop has not been started?

Documentation for waitForStarted():

Blocks until the process has started and the started() signal has been emitted, or until msecs milliseconds have passed.

Code:

int main(int argc, char *argv[])
{

    QCoreApplication a(argc, argv);

    // Exec the i2c command to get the power button status
    QProcess i2cprocess;
    i2cprocess.start("/usr/bin/i2cget -f -y 1 0x4b 0x45");

    // Wait for it to start
    if(!i2cprocess.waitForStarted())
    {
        qDebug() << "Could not start QProcess to check power button status.";
        exit(-1);
    }

    // Wait for it to finish
    bool returnValue = i2cprocess.waitForFinished();
    if ( returnValue )
    {
        QByteArray status = i2cprocess.readAllStandardOutput().trimmed();
        bool ok;
        quint16 hexValue = status.toUInt(&ok, 16);
        qDebug() << "Power button status: " << status << hexValue << (hexValue & 0x01);

        // We want LSB
        exit(hexValue & 0x01);

    }
    else
    {
        qDebug() << "Error, process never completed to check power button status.";
        exit(-1);
    }

    return a.exec();

}
PhilBot
  • 748
  • 18
  • 85
  • 173

2 Answers2

3

Direct signal-slot connections are simply indirect function calls, they have nothing whatsoever to do with event loops.

What the waitForXxxx methods do, though, is to spin a local event loop until the signal fires. The signal is fired from some code that gets notified by the OS that the process state has changed. That code is executed, functionally, "by" the event loop.

Remember that in Qt you can create temporary event loops on a whim - it's a bad practice, and you should never write code that uses waitFor methods. It places requirements on your code that are not normally present - and thus introduces bugs!

The question is then: what is the use of an event loop when waiting for processes to change state? Internally, the process notifications require waiting for native events or callbacks, and those all get handled from an event loop. Even if no events are used, the event loop performs an interruptible sleep that's needed for the OS to deliver callbacks to the application.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
1

The Qt documentation for QProcess states: -

QProcess provides a set of functions which allow it to be used without an event loop, by suspending the calling thread until certain signals are emitted:

waitForStarted() blocks until the process has started.

waitForReadyRead() blocks until new data is available for reading on the current read channel.

waitForBytesWritten() blocks until one payload of data has been written to the process.

waitForFinished() blocks until the process has finished.

Calling these functions from the main thread (the thread that calls QApplication::exec()) may cause your user interface to freeze.

Community
  • 1
  • 1
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • Thank you - how do those certain signals arrive without an event loop? – PhilBot May 28 '15 at 12:53
  • You're not using the signals, just functions. The equivalent signals are [here](http://doc.qt.io/qt-4.8/qprocess.html#signals) If you connect slots to the signals, you'd then need an event loop – TheDarkKnight May 28 '15 at 12:54
  • @PhilBot Just some additional information: you don't need an event loop when you use direct connections. Those act like direct function calls. – thuga May 29 '15 at 07:19
  • This doesn't really answer the question, and citing the documentation is simply muddying the water. Internally, these functions spin an internal event loop (or an equivalent). – Kuba hasn't forgotten Monica May 29 '15 at 15:43