Reader small image

You're reading from  Mastering Qt 5 - Second Edition

Product typeBook
Published inAug 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781788995399
Edition2nd Edition
Languages
Tools
Right arrow
Authors (2):
Guillaume Lazar
Guillaume Lazar
author image
Guillaume Lazar

Guillaume Lazar is a software engineer living in France, near Paris. He has worked in different companies, from start-ups to multinationals, for the last 10 years. He took the opportunity to observe and learn many team organizations and technologies. In 2014, he founded his own software development company at the age of 27. The current hierarchical organization that applies to most companies seems obsolete to him. With his own company, he wants to try a different approach. Although he defines himself as a Qt framework lover, he likes to mix different technologies and platforms. He also spends time on game development, machine learning, and electronics, because "things" become "alive".
Read more about Guillaume Lazar

Robin Penea
Robin Penea
author image
Robin Penea

Robin Penea has been working in the software industry for a more than a decade. He worked in start-ups and large companies with many technologies that ranged from embedded software to web development. Armed with this experience, he wrote the Mastering Qt 5 book to spread what he loves the most about the programming craft: proper design and quality code. The teaching bug has bitten him, and he continues to share what he learned online using videos. When he is not tinkering with some new technology, he is either on a wall, rock-climbing, or playing music on his piano. You can reach him via Twitter @synapticrob.
Read more about Robin Penea

View More author details
Right arrow

Keeping Your Sanity with Multithreading

In previous chapters, we managed to write code without ever relying on threads. It is time to face the beast and truly understand how threading works in Qt. In this chapter, you will develop a multithreaded application that displays a Mandelbrot fractal. It is a heavy computational process that will bring tears to your CPU cores.

In the example project, the user can see the Mandelbrot fractal, zoom in on the picture, and pan around to discover the magic of fractals.

This chapter will cover the following topics:

  • Discovering QThread
  • Flying over Qt multithreading technologies
  • Architecting the Mandelbrot project
  • Defining a Job class with QRunnable
  • Using QThreadPool in MandelbrotCalculator
  • Displaying the fractal with MandelbrotWidget

Discovering QThread

Qt provides a sophisticated threading system. We assume you already know threading basics and the associated issues (deadlocks, threads synchronization, resource sharing, and so on) and we will focus on how Qt implements it.

QThread is the central class of the Qt threading system. A QThread instance manages one thread of execution within the program.

You can subclass QThread to override the run() function, which will be executed in the QThread framework. Here is how you can create and start QThread*:

QThread* thread = new QThread();
thread->start();

The start() function will automatically call the run() function of the thread and emit the started() signal. Only at this point will the new thread of execution be created. When run() is completed, the thread object will emit the finished() signal.

This brings us to a fundamental aspect of QThread: it works seamlessly...

Flying over Qt multithreading technologies

Built upon QThread, several threading technologies are available in Qt. First, to synchronize threads, the usual approach is to use a mutual exclusion (mutex) that will apply for a given resource. Qt provides it by means of the QMutex class. Its usage is straightforward:

QMutex mutex; 
int number = 1; 
 
mutex.lock(); 
number *= 2; 
mutex.unlock(); 

From the mutex.lock() instruction, any other thread trying to lock mutex will wait until mutex.unlock() has been called.

The locking/unlocking mechanism is error-prone in complex code. You can easily forget to unlock a mutex in a specific exit condition, causing a deadlock. To simplify this situation, Qt provides QMutexLocker, which should be used where QMutex needs to be locked:

QMutex mutex; 
QMutexLocker locker(&mutex); 
 
int number = 1; 
number *= 2; 
if (overlyComplicatedCondition...

Architecting the Mandelbrot project

The example project of this chapter is the multithreaded calculation of a Mandelbrot fractal. The user will see the fractal and will be able to pan and zoom in on that window.

Before diving into the code, we need a broad understanding of a fractal and how we are going to achieve its calculation.

The Mandelbrot fractal is a numerical set that works with complex numbers (a + bi). Each pixel is associated with a value calculated through iterations. If this iterated value diverges toward infinity, then the pixel is out of the Mandelbrot set. If not, then the pixel is inside the Mandelbrot set.

A visual representation of the Mandelbrot fractal looks like this:

Every black pixel in this image corresponds to a complex number for which the sequence tends to diverge to an infinite value. The white pixels correspond to complex numbers bounded to a finite...

Defining a Job class with QRunnable

Let's dive into the project's core. To speed up the Mandelbrot picture-generation, we will split the whole computation into multiple jobs. A Job is a request of a specific task. Depending the number of your CPU cores, several jobs will be executed simultaneously. A Job class produces a JobResult function that contains result values. In our project, a Job class generates values for one line of the complete picture. For example, an image resolution of 800 x 600 requires 600 jobs, each one generating 800 values.

Create a C++ header file called JobResult.h:

#include <QSize> 
#include <QVector> 
#include <QPointF>
#include <QMetaType> struct JobResult { JobResult(int valueCount = 1) : areaSize(0, 0), pixelPositionY(0), moveOffset(0, 0), scaleFactor(0.0), values...

Using QThreadPool in MandelbrotCalculator

Now that our Job class is ready to be used, we need to create a class to manage the jobs. Please create a new class, MandelbrotCalculator. Let's see what we need in the MandelbrotCalculator.h file:

#include <QObject> 
#include <QSize> 
#include <QPointF> 
#include <QElapsedTimer> 
#include <QList> 
 
#include "JobResult.h" 
 
class Job; 
 
class MandelbrotCalculator : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit MandelbrotCalculator(QObject *parent = 0); 
    void init(QSize imageSize); 
 
private: 
    QPointF mMoveOffset; 
    double mScaleFactor; 
    QSize mAreaSize; 
    int mIterationMax; 
    int mReceivedJobResults; 
    QList<JobResult> mJobResults; 
    QElapsedTimer mTimer; 
}; 

We have already discussed mMoveOffset, mScaleFactor, mAreaSize, and mIterationMax in the...

Displaying the fractal with MandelbrotWidget

Here we are, the Mandelbrot algorithm is done and the multithreading system is ready to compute complex fractals over all your CPU cores. We can now create the widget that will convert all the JobResult to display a pretty picture.

Create a new C++ class called MandelbrotWidget. For this widget, we will handle the painting ourselves. Thus, we do not need any .ui Qt Designer Form file. Let's begin with the MandelbrotWidget.h file:

#include <memory> 
 
#include <QWidget> 
#include <QPoint> 
#include <QThread> 
#include <QList> 
 
#include "MandelbrotCalculator.h" 
 
class QResizeEvent; 
 
class MandelbrotWidget : public QWidget 
{ 
    Q_OBJECT 
 
public: 
    explicit MandelbrotWidget(QWidget *parent = 0); 
    ~MandelbrotWidget(); 
 
private: 
    MandelbrotCalculator mMandelbrotCalculator...

Summary

In this chapter, you discovered how a QThread class works and learned how to efficiently use tools provided by Qt to create a powerful multithreaded application. Your Mandelbrot application is able to use all the cores of your CPU to compute a picture quickly.

Creating a multithreaded application presents a lot of pitfalls (such as deadlock, event-loop flood, orphan threads, and overhead). The application architecture is important. If you are able to isolate the heavy code that you want to parallelize, everything should go well. Nevertheless, the user experience is of the utmost importance; you will sometimes have to accept a little overhead if your application gives the user a smoother feeling.

In the next chapter, we will see several ways to implement an Inter-Process Communication (IPC) between applications. The project example will enhance your current Mandelbrot application...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering Qt 5 - Second Edition
Published in: Aug 2018Publisher: PacktISBN-13: 9781788995399
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (2)

author image
Guillaume Lazar

Guillaume Lazar is a software engineer living in France, near Paris. He has worked in different companies, from start-ups to multinationals, for the last 10 years. He took the opportunity to observe and learn many team organizations and technologies. In 2014, he founded his own software development company at the age of 27. The current hierarchical organization that applies to most companies seems obsolete to him. With his own company, he wants to try a different approach. Although he defines himself as a Qt framework lover, he likes to mix different technologies and platforms. He also spends time on game development, machine learning, and electronics, because "things" become "alive".
Read more about Guillaume Lazar

author image
Robin Penea

Robin Penea has been working in the software industry for a more than a decade. He worked in start-ups and large companies with many technologies that ranged from embedded software to web development. Armed with this experience, he wrote the Mastering Qt 5 book to spread what he loves the most about the programming craft: proper design and quality code. The teaching bug has bitten him, and he continues to share what he learned online using videos. When he is not tinkering with some new technology, he is either on a wall, rock-climbing, or playing music on his piano. You can reach him via Twitter @synapticrob.
Read more about Robin Penea