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 $ 
[Digg] [Reddit] [DZone]

Leave a comment