×
Namespaces

Variants
Actions
(Difference between revisions)

How to add multithread support to your Qt application

From Nokia Developer Wiki
Jump to: navigation, search
galazzo (Talk | contribs)
(Galazzo -)
hamishwillee (Talk | contribs)
m (Text replace - "<code cpp>" to "<code cpp-qt>")
(6 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Qt]][[Category:Symbian]][[Category:MeeGo]][[Category:Code Examples]]
+
[[Category:Qt]][[Category:Symbian]][[Category:MeeGo Harmattan]][[Category:Code Examples]][[Category:Symbian^3]][[Category:Nokia Belle]][[Category:Threading]]
 +
{{Abstract|This article explains how to use multi-threading on Qt, using the context of the [http://projects.developer.nokia.com/QHdrCamera/ QHdrCamera] for the explanation.}}
 +
{{SeeAlso|
 +
* [[Multi-Threaded Image Processing using Qt Camera]]
 +
* [http://qt-project.org/doc/qt-4.8/thread-basics.html Threading basic] (Qt reference)
 +
* [http://qt-project.org/doc/qt-4.8/threads.html Thread support in Qt] (Qt reference)}}
 
{{ArticleMetaData <!-- v1.2 -->
 
{{ArticleMetaData <!-- v1.2 -->
 
|sourcecode= <!-- Link to example source code e.g. [[Media:The Code Example ZIP.zip]] -->
 
|sourcecode= <!-- Link to example source code e.g. [[Media:The Code Example ZIP.zip]] -->
Line 10: Line 15:
 
|signing=<!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 
|signing=<!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
|keywords= Thread, QThread, QRunnable,QThreadPool
+
|keywords= Thread, QThread, QRunnable, QThreadPool
 
|language= <!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 
|language= <!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 
|translated-by= <!-- [[User:XXXX]] -->
 
|translated-by= <!-- [[User:XXXX]] -->
Line 24: Line 29:
  
 
== Introduction ==
 
== Introduction ==
This article explains how to manage multithread into a mobile application.  [http://projects.developer.nokia.com/QHdrCamera/ QHdrCamera] will be used as showcase.
+
{{Note|This is an entry in the [[PureView Imaging Competition 2012Q2]]}}
  
== Showcase  ==
+
[http://projects.developer.nokia.com/QHdrCamera/ QHdrCamera] is a QML component for creating [http://en.wikipedia.org/wiki/High_dynamic_range_imaging  High Dynamic Range images]. The component captures three photos at different exposure ranges and combines the best-exposed regions in each using appropriate algorithms (see [[QHdrCamera component for High Dynamic Range Imaging]] for more information).
[http://projects.developer.nokia.com/QHdrCamera/ QHdrCamera] is a component component able to create [http://en.wikipedia.org/wiki/High_dynamic_range_imaging  High Dynamic Range images].<br />
+
Basically to do that the component captures three photos at different exposure range mixing them using some algorithms. For further information, please referr to [http://www.developer.nokia.com/Community/Wiki/QHdrCamera_component_for_High_Dynamic_Range_Imaging this article].<br />
+
<br />
+
The capture image in sequence have to be faster than possible. Heach time the QML component will be asked to shot a frame it saves in a default path the captured image and after is ready  to capture another frame.<br />
+
At the end of the three image capturing process, the flow process need to load all three photo into memory for the raw image processing to produce our HDR image.<br />
+
The loading process is very slow, expecially at resolution growing, due to the ( time of writing ) phone memory speed, so this has impacts the overall processing time. If during the next frame shooting application was able to begin the previous saved frame into memory this will reduce the waiting time, enhancing user experience.<br />
+
The solution provided uses [http://qt-project.org/doc/qt-4.8/qrunnable.html QRUnnable] interface and [http://qt-project.org/doc/qt-4.8/qthreadpool.html QThreadPool] class.
+
  
== QRunnable ==
+
The original single-threaded implementation first captured and saved all the images and then loaded them and started calculation of the HDR image. This was very slow, primarily because of the time taken to save and load images on some hardware.  
The QRunnable class is an interface for representing a task or piece of code that needs to be executed, represented by your reimplementation of the run() function.<br />
+
 
QThreadPool executes your code in a separate thread supporting execution of the same QRunnable more than once.
+
Part of the solution to this problem has been to use multi-threading: as soon as the first image is saved we now start loading and processing it. As much of the loading and processing is now concurrent with image capture, the total execution time is much reduced.
 +
 
 +
The solution provided uses [http://qt-project.org/doc/qt-4.8/qrunnable.html QRunnable] interface and [http://qt-project.org/doc/qt-4.8/qthreadpool.html QThreadPool] class.
  
 
== Multithread Image Loading ==
 
== Multithread Image Loading ==
The first step is to implement the QRunnable interface:
+
{{Icode|QRunnable}} is an interface class for new threads - all you need to do is implement its {{Icode|run()}} function with the code that can be run concurrently. The runnable objects are added to the {{Icode|QThreadPool}} which allows the {{Icode|QRunnable}} objects to be re-used (this is more efficient than creating multiple threads).
<code cpp>
+
 
 +
The first step is to implement the {{Icode|QRunnable}} interface:
 +
<code cpp-qt>
 
class LoadingThread : public QRunnable
 
class LoadingThread : public QRunnable
 
{
 
{
Line 70: Line 72:
  
 
=== QThreadPool ===
 
=== QThreadPool ===
The QML Camera component provide the {{Icode|onImageSaved ( path )}} signal, called after the image has been written to the filesystem, in this context connected to {{Icode|setShot}} SLOTs. Here we create the LoadingThread to start in background the into memory loading process.
+
The QML Camera component provides the {{Icode|onImageSaved ( path )}} signal, called after the image has been written to the filesystem, in this context connected to {{Icode|setShot}} slots. Here we create the {{Icode|LoadingThread}} to start memory loading process in the background.
  
<code cpp>
+
<code cpp-qt>
 
void QHdrCamera::setShot1(QString path) {
 
void QHdrCamera::setShot1(QString path) {
 
     if( !QFile::rename(path, QDir::toNativeSeparators(s_shot1)) ) {
 
     if( !QFile::rename(path, QDir::toNativeSeparators(s_shot1)) ) {
Line 104: Line 106:
 
</code>
 
</code>
  
Application have to wait until all threads finish their job. QThreadPool provide a method, called {{Icode|waitForDone()'}} to do that.
+
The application has to wait until all threads finish their jobs. {{Icode|QThreadPool}} provides a method called {{Icode|waitForDone()}} that does that.
<code cpp>
+
 
 +
<code cpp-qt>
 
QThreadPool::globalInstance()->waitForDone();
 
QThreadPool::globalInstance()->waitForDone();
 
</code>
 
</code>
 +
 +
== Summary ==
 +
Multi-threading has enormously improved the performance of the [http://projects.developer.nokia.com/QHdrCamera/ QHdrCamera] QML component by allowing the long running image save/load and initial processing steps to be carried out concurrently with image capture using the camera. Not only is the total execution time reduced, but the perceived behaviour is also better because the UI remains responsive to user input during calculation.
 +
 +
While multi-threading might not always provide a "real" improvement in execution time it is very useful in cases like this, where the different tasks don't need to use the same resources at the same time. Even where the total execution time remains the same, threading should be considered for its benefit of keeping the UI responsive.
 +
 +
Using a {{Icode|QThreadPool}} and {{Icode|QRunnable}} is an efficient way to implement multi-threading on Qt as threads are created when needed and can be re-used.

Revision as of 04:17, 11 October 2012

This article explains how to use multi-threading on Qt, using the context of the QHdrCamera for the explanation.

Article Metadata
Tested with
Devices(s): Nokia C7-00, Nokia N8, Nokia N950
CompatibilityArticle
Keywords: Thread, QThread, QRunnable, QThreadPool
Created: galazzo (21 May 2012)
Last edited: hamishwillee (11 Oct 2012)

Contents

Introduction

Note.pngNote: This is an entry in the PureView Imaging Competition 2012Q2

QHdrCamera is a QML component for creating High Dynamic Range images. The component captures three photos at different exposure ranges and combines the best-exposed regions in each using appropriate algorithms (see QHdrCamera component for High Dynamic Range Imaging for more information).

The original single-threaded implementation first captured and saved all the images and then loaded them and started calculation of the HDR image. This was very slow, primarily because of the time taken to save and load images on some hardware.

Part of the solution to this problem has been to use multi-threading: as soon as the first image is saved we now start loading and processing it. As much of the loading and processing is now concurrent with image capture, the total execution time is much reduced.

The solution provided uses QRunnable interface and QThreadPool class.

Multithread Image Loading

QRunnable is an interface class for new threads - all you need to do is implement its run() function with the code that can be run concurrently. The runnable objects are added to the QThreadPool which allows the QRunnable objects to be re-used (this is more efficient than creating multiple threads).

The first step is to implement the QRunnable interface:

class LoadingThread : public QRunnable
{
public:
LoadingThread(QString*, QImage*);
 
private:
QString* path;
QImage* image;
 
protected:
void run();
};
 
LoadingThread::LoadingThread(QString* path, QImage* image){
this->path = path;
this->image = image;
}
 
void LoadingThread::run() {
if( image->load(*path) ){
qDebug() << "Image loaded";
} else {
qDebug() << "Error during image loading " << *path;
}
}

QThreadPool

The QML Camera component provides the onImageSaved ( path ) signal, called after the image has been written to the filesystem, in this context connected to setShot slots. Here we create the LoadingThread to start memory loading process in the background.

void QHdrCamera::setShot1(QString path) {
if( !QFile::rename(path, QDir::toNativeSeparators(s_shot1)) ) {
qDebug() << "Impossible to rename shot1:" << path;
} else {
LoadingThread* tLoad = new LoadingThread(&s_shot1, &shot1);
QThreadPool::globalInstance()->start(tLoad);
emit savedShot1();
}
}
 
void QHdrCamera::setShot2(QString path) {
if( !QFile::rename(path, s_shot2) ) {
qDebug() << "Impossible to rename shot2";
} else {
LoadingThread* tLoad = new LoadingThread(&s_shot2, &shot2);
QThreadPool::globalInstance()->start(tLoad);
emit savedShot2();
}
}
 
void QHdrCamera::setShot3(QString path) {
if( !QFile::rename(path, s_shot3) ){
qDebug() << "Impossible to rename shot3";
} else {
LoadingThread* tLoad = new LoadingThread(&s_shot3, &shot3);
QThreadPool::globalInstance()->start(tLoad);
emit savedShot3();
}
}

The application has to wait until all threads finish their jobs. QThreadPool provides a method called waitForDone() that does that.

QThreadPool::globalInstance()->waitForDone();

Summary

Multi-threading has enormously improved the performance of the QHdrCamera QML component by allowing the long running image save/load and initial processing steps to be carried out concurrently with image capture using the camera. Not only is the total execution time reduced, but the perceived behaviour is also better because the UI remains responsive to user input during calculation.

While multi-threading might not always provide a "real" improvement in execution time it is very useful in cases like this, where the different tasks don't need to use the same resources at the same time. Even where the total execution time remains the same, threading should be considered for its benefit of keeping the UI responsive.

Using a QThreadPool and QRunnable is an efficient way to implement multi-threading on Qt as threads are created when needed and can be re-used.

257 page views in the last 30 days.
×