11.10.2017

foto Petr Bravenec

Petr Bravenec
Twitter: @BravenecPetr
+420 777 566 384
petr.bravenec@hobrasoft.cz

In previous articles, I have shown the easiest use of parallel calculations in the Qt library. A common feature of all the examples in the previous articles is using of blocking operations.

Different names of the same functions

Look to some functions, which the Qt library offers for parallel programming: (QtConcurrent Namespace):

  • map()
  • mapped()
  • blockingMap()
  • blockingMapped()

The same parallel algorithm is available under four different names. Why?

Functions in QtConcurrent exists in four different variants: with the prefix blocking- and with suffix -ed.

Function ending with -ed (map, blockingMap) work in place. Parallel calculations modifies directly the input data. Functions ending to -ed (mapped, blockingMapped) returns output data. Input data remains untouched.

Blocking operations

Functions begining with blocking- work unless the calculation is not completed. When you call such function, the application continues on next line of code after complete whole parallel calculation.

The same naming conventions exist for all other parallel algorithms. The naming conventions are also apparent with other Qt functions and classes (for example, QString::trimmed() and other).

Blocking parallel calculations can be easily used for batch processing on command line, where usualy the completion of the calculation end entire program and where we are not much interested in the progress of the calculation.

Non-blocking operations

Blocking operations for GUI application are completely unacceptable. The user expects that he could stop, suspend or resume the calculation. Alternatively, the user may just want to know haw long the calculation will be running.

When the non-blocking function is call, the calculation is started but the functions return immediately and program continues with the next line of the code. Event a bit of parallel caculations is not completed when the function returns. The calculations will be done in the background independently of other program activities. During a parallel calculation the GUI is responding. The user can control the application even when the parallel calculation is running.

If the function call is non blocked and the the functions itself only starts the calculation and returns immediately, we have to get the information about the calculation in other way the a simple return from blocking fuction. We can use the QFuture class for that task.

QFuture

Remember, how the Qt parallel calculations are used in the simplest case: the container such as QStringList is prepared and the data is passed to some parallel function, such a map():

QStringList data = readData();
QtConcurrent::blockingMap(data, mapFunkce);

After the calculation, the result values are stored in the data container, When the function map() without the -ed suffix is used, the situation is simple - function map() works in place. I you want to keep the input data untouched, you have to store the output data in the different place. The QFuture class is used to store output data.

But the QFuture is used not only as a container. The QFuture and QFutureWatcher class provides methods for simple calculation control. The calculation can be used to pause and resume or stop using the QFutureWatcher class. When you need only a simple synchronization, the waitForFinished() method can be used:

QStringList data = readData();
QFuture<QString> future = QtConcurrent::map(data, mapFunkce);
future.waitForFinished();
QFutureIterator<QString> iterator(future);
while (iterator.hasNext()) {
    qDebug << iterator.next();
    }

The waitForFinished() method blocks the program until the parallel calculation si complete. The method is similar to blocked functions. I will show the use of QFuture and QFutureWatcher in the next article.

Complete example reads data from standard input and prints all lines with number values:

#include 
#include 
#include 
#include 
#include 

bool isNumber(const QString& text) {
    bool ok;
    text.toInt(&ok);
    return ok;
}

int main(int, char **) {
    QTextStream stream(stdin);
    QList<QString> inputData;
    QString line;
    do {
        line = stream.readLine();
        inputData << line;
        } while (!line.isNull());

    QFuture<QString> future = QtConcurrent::filtered (
            inputData,
            isNumber
            );

    future.waitForFinished();
    QFutureIterator<QString> iterator(future);
    while (iterator.hasNext()) {
        QString x = iterator.next();
        qDebug() << x;
        }
}

Links

Conclusion

This article is one of several articles on parallel programming in Qt. Watch this site, watch our Twitter. Further parts will follow.

Hobrasoft s.r.o. | Contact