# QT Design Patterns

# Thread patterns

# Inheriting QThread

This is the "Java Style", but it's not the best way to do it.

To do this will have to include QThread and substitute the QObject for QThread on the class inheritance.

main.cpp

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>
#include <QThread>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);

signals:

};

#endif // MYCLASS_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

like this:

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>
#include <QThread>

class MyClass : public QThread
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);
    ~MyClass();

signals:

};

#endif // MYCLASS_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

myclass.cpp

#include "myclass.h"

MyClass::MyClass(QObject *parent) : QThread(parent)
{
    qInfo() << this << "Creted on: " << QThread::currentThread(); 
}

MyClass::~MyClass()
{
    qInfo() << this << "Destroyd on: " << QThread::currentThread(); 
}

1
2
3
4
5
6
7
8
9
10
11
12

With this we have changed MyClass from a QObject to a QThread and now I can insert a virtual function, by right click on QThread and Insert Virtual Functions from Base Class, like the run function.


A(major)

The problem with this method is it really breaks the spirit of the cue thread class, this will be done without problem, but you could very easily break this thread by doing something in this run function.

So we are going to just demonstrate here.

main.cpp

#include <QCoreApplication>

/*

  What?
  Inheriting QThread

  Description:
  Not the best idea but it can be done

  Why?
  Java style threads
  Note - This is not the best way!
  You can easily break the thread

  Example:
  Inherit QThread
  https://doc.qt.io/qt-5/qthread.html

*/

#include <QDebug>
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QSharedPointer>
#include "myclass.h"

MyClass *thread;
QTimer *timer;

void timeout()
{
    if (!thread) return;
    if(!timer) return;

    if(thread->isRunning() == true && thread->isFinished() == true)
    {
        qInfo() << "Thread is running!";
    }

    if(thread->isRunning() == false && thread->isFinished() == true)
    {
        qInfo() << "Thread is finished!";
        timer->stop();
        thread->deleteLater();
        timer->deleteLater();
    }
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    thread = new MyClass(&a);
    timer = new QTimer(&a);
    thread->setObjectName("Child Tread");

    timer->setInterval(1000);
    QObject::connect(timer, &QTimer::timeout, timeout);

    timer->start();
    thread->start(); //QThread::start calls QThread::runn()

    // Do other things in the background

    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

output:

MyClass(0x867c90) Creted on:  QThread(0x862d40)
MyClass(0x867c90, name = "Child Tread") Run on:  MyClass(0x867c90, name = "Child Tread")
MyClass(0x867c90, name = "Child Tread") Finished on:  MyClass(0x867c90, name = "Child Tread")
Thread is finished!
MyClass(0x867c90, name = "Child Tread") Destroyd on:  QThread(0x862d40)
1
2
3
4
5

Everything runs fine.

The problem is here:

Lets include a public variable called value:















 












#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>
#include <QThread>

class MyClass : public QThread
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);
    ~MyClass();
    
    int value;

signals:


    // QThread interface
protected:
    void run();
};

#endif // MYCLASS_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Now let's modify value in run() and in main().

myclass.h
















 









#include "myclass.h"

MyClass::MyClass(QObject *parent) : QThread(parent)
{
    qInfo() << this << "Creted on: " << QThread::currentThread();
}

MyClass::~MyClass()
{
    qInfo() << this << "Destroyd on: " << QThread::currentThread();
}

void MyClass::run()
{
    //modify the value
    value= 10;
    
    qInfo() << this << "Run on: " << QThread::currentThread();

    QThread::currentThread()->msleep(5000);

    qInfo() << this << "Finished on: " << QThread::currentThread();

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

main.cpp






































































 




#include <QCoreApplication>


/*

  What?
  Inheriting QThread

  Description:
  Not the best idea but it can be done

  Why?
  Java style threads
  Note - This is not the best way!
  You can easily break the thread

  Example:
  Inherit QThread
  https://doc.qt.io/qt-5/qthread.html

*/


#include <QDebug>
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QSharedPointer>
#include "myclass.h"

MyClass *thread;
QTimer *timer;

void timeout()
{
    if (!thread) return;
    if(!timer) return;

    if(thread->isRunning() == true && thread->isFinished() == true)
    {
        qInfo() << "Thread is running!";
    }

    if(thread->isRunning() == false && thread->isFinished() == true)
    {
        qInfo() << "Thread is finished!";
        timer->stop();
        thread->deleteLater();
        timer->deleteLater();
    }
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    thread = new MyClass(&a);
    timer = new QTimer(&a);
    thread->setObjectName("Child Tread");

    timer->setInterval(1000);
    QObject::connect(timer, &QTimer::timeout, timeout);

    timer->start();
    thread->start(); //QThread::start calls QThread::runn()

    // Do other things in the background
    
    thread->value = 55;

    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

What the actual value is, you have two different threads doing two different things to the same variable that is bad, that's a recipe for threading disaster and that's why I do not recommend doing this.

# QThread moveTo

Now we have 3 distinct objects, an actual QThread the QTimer and MyClass, last time the class was the thread.

main.cpp

#include <QCoreApplication>

/*

  What?
  QObject moveto QThread

  Description
  Not the best idea but it can be done

  Why?
  You do not want to risk breaking the functionality of QTread

  Example
  move an object to a thread

*/

#include <QDebug>
#include <QObject>
#include <QTimer>
#include <QThread>
#include "myclass.h"

QThread *thread;
QTimer *timer;
MyClass *myclass;


void timeout()
{
    if (!thread) return;
    if(!timer) return;

    if(thread->isRunning() == true && thread->isFinished() == false)
    {
        qInfo() << "Thread is running...";
    }

    if(thread->isRunning() == false && thread->isFinished() == true)
    {
        qInfo() << "Thread is Finished!";
        timer->stop();
        thread->deleteLater();
        timer->deleteLater();
        myclass->deleteLater();
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QThread::currentThread()->setObjectName("Main Thread");
    thread = new QThread(&a);
    thread->setObjectName("Child thread");

    timer = new QTimer(&a);
    myclass = new MyClass(nullptr);  //NO PARENT!!!! If it has a parent, you get some sort of crazy cross thread operation and gets really angry really fast.

    QObject::connect(timer, &QTimer::timeout, timeout); //Auto connection
    QObject::connect(thread, &QThread::started, myclass, &MyClass::run, Qt::QueuedConnection);
    QObject::connect(myclass, &MyClass::finished, thread, &QThread::quit, Qt::QueuedConnection);
    //So really what we're doing is we're saying where the thread starts, run the class.
    //When the class finish finished the thread, got a little bit of a loop going there.

    myclass->moveToThread(thread); //will fail if there is a parent
    timer->setInterval(1000);

    timer->start();
    thread->start(); // QThread::start calls QThread::run()

    // Do other things in the background


    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

myclass.h

#ifndef MYCLAS_H
#define MYCLAS_H

#include <QObject>
#include <QThread>
#include <QDebug>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);
    ~MyClass();

signals:
    void finished();

public slots:
    void run();

};

#endif // MYCLAS_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

myclass.cpp

#include "myclass.h"

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    qInfo() << this << "Created on " << QThread::currentThread();
}

MyClass::~MyClass()
{
    qInfo() << this << "Destroyed on " << QThread::currentThread();
}

void MyClass::run()
{
    qInfo() << this << "Run on: " << QThread::currentThread();

    // Do tread stuff here
    QThread::currentThread()->msleep(5000);

    qInfo() << this << "Finished on: " << QThread::currentThread();

    //use signals and slots
    emit finished();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

output

MyClass(0xfa7fb0) Created on  QThread(0xfa2d40, name = "Main Thread")
MyClass(0xfa7fb0) Run on:  QThread(0xfa7d10, name = "Child thread")
Thread is running...
Thread is running...
Thread is running...
Thread is running...
Thread is running...
MyClass(0xfa7fb0) Finished on:  QThread(0xfa7d10, name = "Child thread")
Thread is Finished!
1
2
3
4
5
6
7
8
9

TIP

Auto Connect is awesome these days.

So if you've run into problems with that, make sure using a cute connection, general practice, because I'm very distrusting, I tend to force the cute connection regardless.

QObject::connect(myclass, &MyClass::finished, thread, &QThread::quit); // autoconnection

QObject::connect(myclass, &MyClass::finished, thread, &QThread::quit, Qt::QueuedConnection);

# QThreadPool

To use one of the QThreadPool threads, subclass QRunnable and implement the run() virtual function. Then create an object of that class and pass it to QThreadPool::start().

We're going to inherit QRunnable, so now we have the best of both worlds. We have a QRunnable, which can run inside of a thread pool and a QObject which can use signals of slots.










 











#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QThread>
#include <QRunnable>
#include <QDebug>
#include <QRandomGenerator>

class MyClass : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);

signals:

};

#endif // MYCLASS_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Noticed something right off the bat, the class already exists, but we're pretty much expecting its full life cycle of functionality, I should say, in the run function, because this is what happens on the thread, everything outside of run. Or that is not called within run is outside of the threat pool.

myclass.cpp

#include "myclass.h"

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    qInfo() << this << "Created on " << QThread::currentThread();
}

MyClass::~MyClass()
{
    qInfo() << this << "Destroyed on " << QThread::currentThread();
}

void MyClass::run()
{
    qInfo() << this << "Run on " << QThread::currentThread();
    
    emit started();
    
    //Do thread stuff here
    for(int i = 0; i < 10; i++)
    {
        int value = QRandomGenerator::global()->bounded(200);
        QThread::currentThread()->msleep(value);
        qInfo() << this << "Progress " << i << "on" << QThread::currentThread();
    }
    
    emit finished();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

All we're really doing is saying for I equals zero to 10, we're going to make a random number between zero and two hundred and then we're going to put this current thread to sleep.Now, this is the pulled thread, meaning this is a thread inside of the thread pool.

And unfortunately, even though we can grab the current thread that we're on, we don't have a whole lot of control over it because remember, this is managed by the thread pool.

Now we are going to make the actual pool:

Remember, a pool is a list and internal list of reusable objects.

You're going to see real quick that we have a very small amount of max threads, typically this is the same amount as the processor that you have in here.

Real simple, we're just going to connect myclass to the middle class manager. So my class started to this started my class progress to this progress and finish to finish.

        connect(myclass, &MyClass::started, this, &MyClassManager::started, Qt::QueuedConnection);
        connect(myclass, &MyClass::progress, this, &MyClassManager::progress, Qt::QueuedConnection);
        connect(myclass, &MyClass::finished, this, &MyClassManager::finished, Qt::QueuedConnection);
1
2
3

TIP

myclass, is going to run in the pulled thread and these slots run on the main thread.

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QThread>
#include <QRunnable>
#include <QDebug>
#include <QRandomGenerator>

class MyClass : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);
    ~MyClass();

signals:
    void started();
    void finished();
    void progress(int value);


    // QRunnable interface
public:
    void run();
};

#endif // MYCLASS_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

myclass.cpp

#include "myclass.h"

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    qInfo() << this << "Created on " << QThread::currentThread();
}

MyClass::~MyClass()
{
    qInfo() << this << "Destroyed on " << QThread::currentThread();
}

void MyClass::run()
{
    
    //What happens in the thread stays in the thread
    
    qInfo() << this << "Run on " << QThread::currentThread();

    emit started();

    //Do thread stuff here
    for(int i = 0; i < 10; i++)
    {
        int value = QRandomGenerator::global()->bounded(200);
        QThread::currentThread()->msleep(value);
        qInfo() << this << "Progress " << i << "on" << QThread::currentThread();
    }



    emit finished();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

myclassmanager.h

#ifndef MYCLASSMANAGER_H
#define MYCLASSMANAGER_H

#include <QObject>
#include <QThreadPool>
#include <QRunnable>
#include "myclass.h"

class MyClassManager : public QObject
{
    Q_OBJECT
public:
    explicit MyClassManager(QObject *parent = nullptr);

    void run();

signals:

public slots:
    void started();
    void finished();
    void progress(int value);

};

#endif // MYCLASSMANAGER_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

myclassmanager.cpp

#include "myclassmanager.h"

MyClassManager::MyClassManager(QObject *parent) : QObject(parent)
{

}

void MyClassManager::run()
{
    qInfo() << "Max Threads " << QThreadPool::globalInstance()->maxThreadCount();
    for(int i = 0; i < 25; i++)
    {
        MyClass *myclass = new MyClass(nullptr); // No Parent
        myclass->setAutoDelete(false); // true will cause issues in this video

        myclass->setObjectName("MyClass" + QString::number(i));

        connect(myclass, &MyClass::started, this, &MyClassManager::started, Qt::QueuedConnection);
        connect(myclass, &MyClass::progress, this, &MyClassManager::progress, Qt::QueuedConnection);
        connect(myclass, &MyClass::finished, this, &MyClassManager::finished, Qt::QueuedConnection);

        QThreadPool::globalInstance()->start(myclass);  //The apps global thread pool
    }
}

void MyClassManager::started()
{
    MyClass * myclass = qobject_cast<MyClass*>(sender());
    if(!myclass) return;

    //This is on the main thread!
    qInfo()  << myclass  << "Started slot" << QThread::currentThread();
}

void MyClassManager::finished()
{
    MyClass * myclass = qobject_cast<MyClass*>(sender());
    if(!myclass) return;

    //This is on the main thread!
    qInfo()  << myclass  << "Finished slot" << QThread::currentThread();

    //done eith our object
    myclass->deleteLater();  //on the maiun thread
}

void MyClassManager::progress(int value)
{
    MyClass * myclass = qobject_cast<MyClass*>(sender());
    if(!myclass) return;

    //This is on the main thread!
    qInfo()  << myclass  << "Progress slot: " << value << QThread::currentThread();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

So we have 12 max threads in our pool and each of these threads is getting reused. So you can see we have a whole bunch of creations on the main thread and then started on the main threat and then, boom, everything's running in the pool threads and you can see the different memory addresses of those pulled threads.

And then we just have a whole lot of noise and then we start seeing where things are finishing, they're destroyed now, that's how it's destroyed on the main thread.

Max Threads  12
MyClass(0x27035f0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf490c0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x27035f0, name = "MyClass0") Run on  QThreadPoolThread(0xf48f10, name = "Thread (pooled)")
MyClass(0xf49210) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf490c0, name = "MyClass1") Run on  QThreadPoolThread(0xf48fa0, name = "Thread (pooled)")
MyClass(0xf49060) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf49210, name = "MyClass2") Run on  QThreadPoolThread(0xf49030, name = "Thread (pooled)")
MyClass(0xf4b140) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf49060, name = "MyClass3") Run on  QThreadPoolThread(0xf4b5c0, name = "Thread (pooled)")
MyClass(0xf4b260) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b140, name = "MyClass4") Run on  QThreadPoolThread(0xf4b230, name = "Thread (pooled)")
MyClass(0xf4b1a0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b260, name = "MyClass5") Run on  QThreadPoolThread(0xf4b650, name = "Thread (pooled)")
MyClass(0xf4b500) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b1a0, name = "MyClass6") Run on  QThreadPoolThread(0xf4b6b0, name = "Thread (pooled)")
MyClass(0xf490c0, name = "MyClass1") Progress  0 on QThreadPoolThread(0xf48fa0, name = "Thread (pooled)")
MyClass(0xf4b560) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b500, name = "MyClass7") Run on  QThreadPoolThread(0xf4b380, name = "Thread (pooled)")
MyClass(0xf4b0b0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b560, name = "MyClass8") Run on  QThreadPoolThread(0xf4b590, name = "Thread (pooled)")
MyClass(0xf49210, name = "MyClass2") Progress  0 on QThreadPoolThread(0xf49030, name = "Thread (pooled)")
MyClass(0x27089b0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b0b0, name = "MyClass9") Run on  QThreadPoolThread(0xf4b440, name = "Thread (pooled)")
MyClass(0x2708950) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x27089b0, name = "MyClass10") Run on  QThreadPoolThread(0x2708c80, name = "Thread (pooled)")
MyClass(0x2708b30) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x2708950, name = "MyClass11") Run on  QThreadPoolThread(0x2708a10, name = "Thread (pooled)")
MyClass(0x2708740) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf49210, name = "MyClass2") Progress  1 on QThreadPoolThread(0xf49030, name = "Thread (pooled)")
MyClass(0xf4b500, name = "MyClass7") Progress  0 on QThreadPoolThread(0xf4b380, name = "Thread (pooled)")
MyClass(0x27089b0, name = "MyClass10") Progress  0 on QThreadPoolThread(0x2708c80, name = "Thread (pooled)")
MyClass(0x2710b30) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b560, name = "MyClass8") Progress  0 on QThreadPoolThread(0xf4b590, name = "Thread (pooled)")
MyClass(0x27121a0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x27121d0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x2711f60) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x27035f0, name = "MyClass0") Progress  0 on QThreadPoolThread(0xf48f10, name = "Thread (pooled)")
MyClass(0xf4b140, name = "MyClass4") Progress  0 on QThreadPoolThread(0xf4b230, name = "Thread (pooled)")
MyClass(0x2712020) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270f9c0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270f870) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270f8a0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270fb70) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270fcb0) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0x270fe60) Created on  QThread(0xf42d40, name = "Main Thread")
MyClass(0xf490c0, name = "MyClass1") Progress  1 on QThreadPoolThread(0xf48fa0, name = "Thread (pooled)")
MyClass(0xf4b260, name = "MyClass5") Progress  0 on QThreadPoolThread(0xf4b650, name = "Thread (pooled)")
MyClass(0x27035f0, name = "MyClass0") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b560, name = "MyClass8") Progress  1 on QThreadPoolThread(0xf4b590, name = "Thread (pooled)")
MyClass(0xf490c0, name = "MyClass1") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf49210, name = "MyClass2") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b140, name = "MyClass4") Progress  1 on QThreadPoolThread(0xf4b230, name = "Thread (pooled)")
MyClass(0xf49060, name = "MyClass3") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b140, name = "MyClass4") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b260, name = "MyClass5") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b1a0, name = "MyClass6") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b500, name = "MyClass7") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b560, name = "MyClass8") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b0b0, name = "MyClass9") Progress  0 on QThreadPoolThread(0xf4b440, name = "Thread (pooled)")
MyClass(0xf49060, name = "MyClass3") Progress  0 on QThreadPoolThread(0xf4b5c0, name = "Thread (pooled)")
MyClass(0xf4b0b0, name = "MyClass9") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b500, name = "MyClass7") Progress  1 on QThreadPoolThread(0xf4b380, name = "Thread (pooled)")
MyClass(0x27089b0, name = "MyClass10") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0x2708950, name = "MyClass11") Started slot QThread(0xf42d40, name = "Main Thread")
MyClass(0xf4b1a0, name = "MyClass6") Progress  0 on QThreadPoolThread(0xf4b6b0, name = "Thread (pooled)"

...
 
 name = "Thread (pooled)")
MyClass(0x270fe60, name = "MyClass24") Progress  9 on QThreadPoolThread(0xf4b590, name = "Thread (pooled)")
MyClass(0x270fe60, name = "MyClass24") Finished slot QThread(0xf42d40, name = "Main Thread")
MyClass(0x270fe60, name = "MyClass24") Destroyed on  QThread(0xf42d40, name = "Main Thread")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

# QT Concurrent

First thing is to include the Concurrent library in the project.

cmake:

cmake_minimum_required(VERSION 3.14)

project(qt5dp-6-4 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt5Core)

find_package(Qt5 COMPONENTS Concurrent REQUIRED)

add_executable(qt5dp-6-4
  main.cpp
)
target_link_libraries(qt5dp-6-4 Qt${QT_VERSION_MAJOR}::Core)
target_link_libraries(qt5dp-6-4 PRIVATE Qt5::Concurrent)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

TIP

performscan

Signals and slots, you typically would not have some sort of return value.

When we're not working with slots, we're working with a function.

We want to take this function and make it threaded.

TIP

QFuture<qint64> future = QtConcurrent::run(this, &FileScanner::performscan, path);

To break it down, QFeature says, in the future, we want an qint64, our future is going to be qt(QtConcurrent::run()), go do something (&FileScanner::performscan), make this thing awesome.

This object(this), this function (performscan) with this parameter(path), which is actually this guy right here:


1

Now, I'm going to grab this off the screen pasted in. Simply put, the main thread is not blocked.

In the background, this runs on a thread pool. So what's really happening is QtConcurrent has the global thread pool. It's making a runnable for us. It's putting this on the runnable, running it and then returning the value.

NoDotAndDotDot

If you're wondering what that is, when you're in a directory, the first item is a dot. The second item is a dot dot, which means current and parent. And we don't want to like double scan the current and scan upwards. So we're going to ignore those and that we want to do only folders.

filescan.h

#ifndef FILESCANNER_H
#define FILESCANNER_H

#include <QObject>
#include <QDebug>
#include <QFileInfo>
#include <QDir>
#include <QtConcurrent>
#include <QFuture>


class FileScanner : public QObject
{
    Q_OBJECT
public:
    explicit FileScanner(QObject *parent = nullptr);

    void scan(QString path);

signals:
    void updated(int count);

private:
    qint64 performscan(QString path); //Function to be threaded
    qint64 m_count;
};

#endif // FILESCANNER_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

filescan.cpp:

#include "filescanner.h"

FileScanner::FileScanner(QObject *parent) : QObject(parent)
{

}

void FileScanner::scan(QString path)
{
    qInfo() << "scan on" << QThread::currentThread();
    m_count = 0;

    // This could take a long time
    QFuture<qint64> future = QtConcurrent::run(this, &FileScanner::performscan, path);

    //Main thread in not blocked, we can do other things
    qInfo() << "Main thread is free to do other things...";


    qInfo() << "Result: " << future.result(); //get the result from the Concurrent thread
}

qint64 FileScanner::performscan(QString path)
{
    qint64 value = 0;
    QDir dir(path);

    if(!dir.exists()) return -1;
    qInfo() << "performing scan on" << QThread::currentThread();

    QFileInfoList list = dir.entryInfoList(QDir:: NoDotAndDotDot | QDir::Dirs);
    value = list.length();

    foreach(QFileInfo item, list)
    {
        value = value + performscan(item.filePath());
    }

    return value;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

main.cpp

#include <QCoreApplication>

/*
    What?
    Qt Concurrent

    Description:
    High level threading

    Why?
    Threads are complicated

    Example
    Folder Counter
    QT += concurrent
*/

#include <QObject>
#include <QFileInfo>
#include <QTextStream>
#include <QThread>
#include "filescanner.h"


QString getPath()
{
    QTextStream stream(stdin);

    qInfo() << "Plese enter a path:";
    QString value = stream.readLine();
    QFileInfo fi(value);
    if(!fi.exists())
    {
        qWarning() << "Not a valid path!";
        value.clear();
    }

    return value;
}


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QThread::currentThread()->setObjectName("Main Thread");

    QString path = getPath();
    while (path.isEmpty()) {
        path = getPath();
    }

    qInfo() << path;

    FileScanner fs;
    fs.scan(path);

    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

output:

Plese enter a path:
Desktop
Not a valid path!
Plese enter a path:
C:\Users\Thiago Souto\Desktop\SKINNY ROBOT
"C:\\Users\\Thiago Souto\\Desktop\\SKINNY ROBOT"
scan on QThread(0xf22d40, name = "Main Thread")
Main thread is free to do other things...
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")

...

performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
performing scan on QThreadPoolThread(0x2753d10, name = "Thread (pooled)")
Result:  263

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30