# 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
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
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();
}
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.
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();
}
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)
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
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();
}
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();
}
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();
}
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
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();
}
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!
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
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();
}
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);
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
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();
}
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
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();
}
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")
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)
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:
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
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;
}
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();
}
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
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