Multi-Threaded Programming with QtConcurrent
I’m really looking forward to QtConcurrent which will be in Qt 4.4; so I downloaded a Qt snapshot to try it out.
You can download all of the example code I wrote here, Qt Concurrent Examples
Note: I’ll be calling waitForFinished() in a few of my examples. In an actual application where the function your are calling takes some non-insignificant amount of time to return you would probably want to use QFutureWatcher to monitor the status of the QFuture.
QtConcurrent::map Example
QtConcurrent::map is used to iterate over a container or sequence and call a function on each element of the container. It is expected that your function will modify the element it is called upon in some way. In this example I wrote a simple functor that replaces each string with its upper-cased version.
#include <QtConcurrentMap> #include <QStringList> #include <QCoreApplication> #include <functional> namespace { struct UpcaseString : public std::unary_function<const QString&,void> { void operator()(QString & str) { str = str.toUpper(); } }; } int main() { QStringList strings; strings << "foo" << "bar" << "baz"; QFuture<void> res = QtConcurrent::map(strings,UpcaseString()); res.waitForFinished(); for(QStringList::iterator i = strings.begin(); i != strings.end(); ++i) qDebug("%s",qPrintable(*i)); }
And our results,
~/mapreduce/qtconcurrentMapExample $ ./qtconcurrentMapExample FOO BAR BAZ ~/mapreduce/qtconcurrentMapExample $
QtConcurrent::mapped Example
QtConcurrent::mapped iterates over a container or sequence and accumulates the results of a function into another sequence. This other sequence, stored in the QFuture, can then be iterated over to retrieve the results.
#include <QtConcurrentMap> #include <QStringList> #include <QCoreApplication> #include <functional> namespace { struct UpcaseString : public std::unary_function<const QString&,QString> { QString operator()(const QString & str) { return str.toUpper(); } }; } int main() { QStringList strings; strings << "foo" << "bar" << "baz"; QFuture<QString> res = QtConcurrent::mapped(strings,UpcaseString()); res.waitForFinished(); for (QFuture<QString>::const_iterator i = res.begin(); i != res.end(); ++i) qDebug("%s",qPrintable(*i)); }
And again, our results,
~/mapreduce/qtconcurrentMappedExample $ ./qtconcurrentMappedExample FOO BAR BAZ ~/mapreduce/qtconcurrentMappedExample $
QtConcurrent::mappedReduced Example
And finally a quick example of mappedReduced. The key difference in mappedReduced is that a second function is provided that is used to reduce the intermediate results. In this example I just used a function that concatenates strings; the end result is an upper-cased, concatenated string.
#include <QtConcurrentMap> #include <QStringList> #include <QCoreApplication> #include <functional> namespace { struct UpcaseString : public std::unary_function<const QString&,QString> { QString operator()(const QString & str) const { return str.toUpper(); } }; void concatStrings(QString & result, const QString & str) { result += str; } } int main() { QStringList strings; strings << "foo" << "bar" << "baz"; QFuture<QString> res = QtConcurrent::mappedReduced(strings,UpcaseString(),&concatStrings); res.waitForFinished(); qDebug("%s",qPrintable(res.result())); }
And our results,
~/mapreduce/qtconcurrentMappedReduceExample $ ./qtconcurrentMappedReduceExample FOOBARBAZ ~/mapreduce/qtconcurrentMappedReduceExample $
Leave a comment