Skip to content

Instantly share code, notes, and snippets.

@benlau
Last active April 20, 2017 05:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benlau/cb1cc2adae75aa8a9590315e0f5a66cd to your computer and use it in GitHub Desktop.
Save benlau/cb1cc2adae75aa8a9590315e0f5a66cd to your computer and use it in GitHub Desktop.
// Example code in the article of "Multithreaded Programming with Future & Promise"
// http://blog.qt.io/blog/2017/04/18/multithreaded-programming-future-promise/#comments
/* Step 1 - An ImageReader class */
class ImageReader : public QObject {
public:
QFuture<QImage> read(const QString& fileName);
};
QFuture<QImage> ImageReader::read(const QString &fileName)
{
auto readImageWorker = [](const QString &fileName) {
QImage image;
image.load(fileName);
return image;
};
return QtConcurrent::run(readImageWorker, fileName);
}
// Example of use
{
ImageReader reader;
QFuture<QImage> future = reader.read(INPUT);
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>();
QObject::connect(watcher, &QFutureWatcher<QImage>::finished,
[=]() {
setImage(future.result());
});
watcher->setFuture(future);
}
/* Step 2 - Image Caching (without AsyncFuture) */
class ImageReader : public QObject {
public:
bool isCached(const QString& fileName) const;
QImage readCache(const QString& fileName) const;
QFuture<QImage> read(const QString& fileName);
private:
QMap<QString,QImage> m_cache;
};
QFuture<QImage> ImageReader::read(const QString &fileName)
{
auto readImageWorker = [](const QString &fileName) {
QImage image;
image.load(fileName);
return image;
};
QFuture<QImage> future = QtConcurrent::run(readImageWorker, fileName);
QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
auto updateCache = [=]() {
m_cache[fileName] = future.result();
watcher->deleteLater();
};
connect(watcher, &QFutureWatcher<QImage>::finished, updateCache);
watcher->setFuture(future);
return future;
}
bool ImageReader::isCached(const QString &fileName) const
{
return m_cache.contains(fileName);
}
QImage ImageReader::readCache(const QString &fileName) const
{
return m_cache[fileName];
}
/* Step 3 - Image Caching with AsyncFuture */
class ImageReader : public QObject {
public:
QFuture<QImage> read(const QString& fileName);
private:
QMap<QString,QImage> m_cache;
QMap<QString, QFuture<QImage>> m_futures;
};
QFuture<QImage> ImageReader::read(const QString &fileName)
{
if (m_cache.contains(fileName)) {
// Cache hit. Return an already finished QFuture object with the image
auto defer = AsyncFuture::deferred<QImage>();
defer.complete(m_cache[fileName]);
return defer.future();
}
if (m_futures.contains(fileName)) {
// It is loading. Return the running QFuture
return m_futures[fileName];
}
auto readImageWorker = [](const QString &fileName) {
QImage image;
image.load(fileName);
return image;
};
auto updateCache = [=](QImage result) {
m_cache[fileName] = result;
m_futures.remove(fileName);
return result;
};
QFuture<QImage> future = AsyncFuture::observe(QtConcurrent::run(readImageWorker, fileName)).subscribe(updateCache).future();
m_futures[fileName] = future;
return future;
}
/* Step 4 - ImageReader with readScaled function */
class ImageReader : public QObject {
public:
QFuture<QImage> read(const QString& fileName);
QFuture<QImage> readScaled(const QString& fileName, const QSize& size);
private:
QMap<QString,QImage> m_cache;
QMap<QString, QFuture<QImage>> m_futures;
};
QFuture<QImage> ImageReader::read(const QString &fileName)
{
if (m_cache.contains(fileName)) {
// Cache hit. Return an already finished QFuture object with the image
auto defer = AsyncFuture::deferred<QImage>();
defer.complete(m_cache[fileName]);
return defer.future();
}
if (m_futures.contains(fileName)) {
// It is loading. Return the running QFuture
return m_futures[fileName];
}
auto readImageWorker = [](const QString &fileName) {
QImage image;
image.load(fileName);
return image;
};
auto updateCache = [=](QImage result) {
m_cache[fileName] = result;
m_futures.remove(fileName);
return result;
};
QFuture<QImage> future = AsyncFuture::observe(QtConcurrent::run(readImageWorker, fileName)).subscribe(updateCache).future();
m_futures[fileName] = future;
return future;
}
QFuture<QImage> ImageReader::readScaled(const QString &fileName, const QSize &size)
{
auto scaleImageWorker = [=](QImage input) {
// Run in worker thread
return input.scaled(size);
};
auto callback = [=](QImage result) {
// Run in main thread
return QtConcurrent::run(scaleImageWorker, result);
};
QFuture<QImage> input = read(fileName);
QFuture<QImage> output = AsyncFuture::observe(input).subscribe(callback).future();
return output;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment