I understand how QThread
is supposed to be used conceptually, with something akin to the following
MyWorker *worker = new MyWorker();
QThread *thread = new QThread();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(done()), thread, SLOT(quit()));
connect(worker, SIGNAL(done()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
which will execute the doWork()
method within MyWorker
within the thread
, stopping the thread and performing memory cleanup once worker
announces it's done via done()
. This is how I've seen all examples, and it really appears geared towards a Worker does an operation in a separate thread type of use case.
Based on what I've understood:
Qt::AutoConnection
will useQt::DirectConnection
if the signal and slot objects live in the same threadQt::AutoConnection
will useQt::QueuedConnection
if the signal and slot objects live in a different threadQt::DirectConnection
will execute the destination slot in the same thread as the source signalQt::QueuedConnection
will queue the signal such that it will (eventually) be executed within the event loop of destination slot's threadmoveToThread()
"relocates" an object from its current thread into the specified one- A
QThread
will remain active (regardless of the objects within) untilQThread::quit()
is called (which is why theconnect
toSLOT(quit())
in the above code example is so important
So this leads me to two questions for a potential use case which feels like it goes a little against the prescribe QThread
formula, and which I haven't really been able to find discussed anywhere.
Question 1 - Would simply moving the object just allow for slots to execute in the new thread?
By this I mean:
MyWorker *worker = new MyWorker();
QThread *workerThread = new QThread();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished(), thread, SLOT(deleteLater()));
workerThread->start();
In the above, there is no dedicated "execute" slot/method within MyWorker
, meaning that it would perform any triggers slots in thread
(provided the connection was done using Qt::AutoConnection
or Qt::QueuedConnection
of course). Thus if elsewhere in the code I were to do:
MyTrigger trigger;
connect(&trigger, SIGNAL(triggered()), worker, SLOT(doSomething()));
then any time trigger
would emit the triggered()
signal, worker
would execute the doSomething()
slot within workerThread
rather than whatever thread is trigger
belongs to? Thus, slot processing would be multi-threaded without there being an explicit doWork()
item to be executed in the thread.
Note: I can see the issues with memory management in the example above, but this is just purely an illustration of the idea.
I'm fairly confident that this would be the case, and if so this leads me to my next question...
Question 2 - What thread is an object created in?
Or perhaps a slightly different way to phrase this would be, can I ensure that objects are created in a particular thread? Continuing from the above example, let's say that I want to replace MyWorker
with some kind of wider capability, where I want the whole capability to operate in this separate thread. I'm thinking of essentially expanding on the above idea, but rather than using a single class, leveraging a series of classes, all of which are built-out from a central class. What I'm thinking is something along the lines of
class MyCapability: public QObject {
Q_OBJECT
public:
MyOtherWorker* getOtherWorker() {
return worker2;
}
public slots:
void setup() {
worker1 = new MyWorker();
worker2 = new MyOtherWorker();
connect(worker1, SIGNAL(something()), worker2, SLOT(other()));
}
void doSomething() {
worker1->doSomething();
}
private:
MyWorker *worker1;
MyOtherWorker *worker2;
};
MyCapability *capability = new MyCapability();
QThread *capabilityThread = new QThread();
capability->moveToThread(capabilityThread);
connect(capabilityThread, SIGNAL(started()), capability, SLOT(setup()));
connect(capabilityThread, SIGNAL(finished()), capability, SLOT(deleteLater()));
connect(capabilityThread, SIGNAL(finished(), thread, SLOT(deleteLater()));
capabilityThread->start();
Thus:
capability
will live in thecapabilityThread
- since
MyCapability::setup()
is called withincapabilityThread
anything created within will belong tocapabilityThread
as well worker1::something()
connects toworker2::other()
asQt::DirectConnection
as they are within the same thread
When this is used from external
MyTrigger trigger;
connect(&trigger, SIGNAL(doSomethingTrigger()), capability, SLOT(doSomething()));
connect(&trigger, SIGNAL(doOtherTrigger()), capability->getOtherWorker(), SLOT(other()));
trigger
will be connecting via Qt::QueueConnection
as capability
, worker1
, and worker2
all live within the capabilityThread
(assuming trigger
is in a different one).
What I'm thinking is creating a "pocket" of functionality in this manner that exists in a single thread, separate from the rest of the application, such that the rest of the application can largely ignore what thread it may (or may not) live in, but which will perform its processing/execution in its dedicated thread via signals/slots in a safe and reliable manner.
Note: again, this example code is a bit of a minefield in terms of memory stability/management, but I'm trying to make sure that my understanding of the QThread
concepts is correct.
Is my understanding on these two fronts correct? What mistaken assumptions am I working from?
Thanks!
I understand how QThread
is supposed to be used conceptually, with something akin to the following
MyWorker *worker = new MyWorker();
QThread *thread = new QThread();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(done()), thread, SLOT(quit()));
connect(worker, SIGNAL(done()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
which will execute the doWork()
method within MyWorker
within the thread
, stopping the thread and performing memory cleanup once worker
announces it's done via done()
. This is how I've seen all examples, and it really appears geared towards a Worker does an operation in a separate thread type of use case.
Based on what I've understood:
Qt::AutoConnection
will useQt::DirectConnection
if the signal and slot objects live in the same threadQt::AutoConnection
will useQt::QueuedConnection
if the signal and slot objects live in a different threadQt::DirectConnection
will execute the destination slot in the same thread as the source signalQt::QueuedConnection
will queue the signal such that it will (eventually) be executed within the event loop of destination slot's threadmoveToThread()
"relocates" an object from its current thread into the specified one- A
QThread
will remain active (regardless of the objects within) untilQThread::quit()
is called (which is why theconnect
toSLOT(quit())
in the above code example is so important
So this leads me to two questions for a potential use case which feels like it goes a little against the prescribe QThread
formula, and which I haven't really been able to find discussed anywhere.
Question 1 - Would simply moving the object just allow for slots to execute in the new thread?
By this I mean:
MyWorker *worker = new MyWorker();
QThread *workerThread = new QThread();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished(), thread, SLOT(deleteLater()));
workerThread->start();
In the above, there is no dedicated "execute" slot/method within MyWorker
, meaning that it would perform any triggers slots in thread
(provided the connection was done using Qt::AutoConnection
or Qt::QueuedConnection
of course). Thus if elsewhere in the code I were to do:
MyTrigger trigger;
connect(&trigger, SIGNAL(triggered()), worker, SLOT(doSomething()));
then any time trigger
would emit the triggered()
signal, worker
would execute the doSomething()
slot within workerThread
rather than whatever thread is trigger
belongs to? Thus, slot processing would be multi-threaded without there being an explicit doWork()
item to be executed in the thread.
Note: I can see the issues with memory management in the example above, but this is just purely an illustration of the idea.
I'm fairly confident that this would be the case, and if so this leads me to my next question...
Question 2 - What thread is an object created in?
Or perhaps a slightly different way to phrase this would be, can I ensure that objects are created in a particular thread? Continuing from the above example, let's say that I want to replace MyWorker
with some kind of wider capability, where I want the whole capability to operate in this separate thread. I'm thinking of essentially expanding on the above idea, but rather than using a single class, leveraging a series of classes, all of which are built-out from a central class. What I'm thinking is something along the lines of
class MyCapability: public QObject {
Q_OBJECT
public:
MyOtherWorker* getOtherWorker() {
return worker2;
}
public slots:
void setup() {
worker1 = new MyWorker();
worker2 = new MyOtherWorker();
connect(worker1, SIGNAL(something()), worker2, SLOT(other()));
}
void doSomething() {
worker1->doSomething();
}
private:
MyWorker *worker1;
MyOtherWorker *worker2;
};
MyCapability *capability = new MyCapability();
QThread *capabilityThread = new QThread();
capability->moveToThread(capabilityThread);
connect(capabilityThread, SIGNAL(started()), capability, SLOT(setup()));
connect(capabilityThread, SIGNAL(finished()), capability, SLOT(deleteLater()));
connect(capabilityThread, SIGNAL(finished(), thread, SLOT(deleteLater()));
capabilityThread->start();
Thus:
capability
will live in thecapabilityThread
- since
MyCapability::setup()
is called withincapabilityThread
anything created within will belong tocapabilityThread
as well worker1::something()
connects toworker2::other()
asQt::DirectConnection
as they are within the same thread
When this is used from external
MyTrigger trigger;
connect(&trigger, SIGNAL(doSomethingTrigger()), capability, SLOT(doSomething()));
connect(&trigger, SIGNAL(doOtherTrigger()), capability->getOtherWorker(), SLOT(other()));
trigger
will be connecting via Qt::QueueConnection
as capability
, worker1
, and worker2
all live within the capabilityThread
(assuming trigger
is in a different one).
What I'm thinking is creating a "pocket" of functionality in this manner that exists in a single thread, separate from the rest of the application, such that the rest of the application can largely ignore what thread it may (or may not) live in, but which will perform its processing/execution in its dedicated thread via signals/slots in a safe and reliable manner.
Note: again, this example code is a bit of a minefield in terms of memory stability/management, but I'm trying to make sure that my understanding of the QThread
concepts is correct.
Is my understanding on these two fronts correct? What mistaken assumptions am I working from?
Thanks!
Share Improve this question edited Mar 11 at 14:21 Some programmer dude 410k36 gold badges414 silver badges644 bronze badges asked Mar 11 at 14:15 cancechcancech 1077 bronze badges 3 |1 Answer
Reset to default 4Thus, slot processing would be multi-threaded without there being an explicit doWork() item to be executed in the thread
Yes, whole point of workers is to not have explicit while (haveWork()) doWork()
(it's kinda still there though), just an eventloop that ready to execute tasks as soon as they arrive.
What thread is an object created in?
Function creates an object in a thread it runs in (current thread). setup()
will be executed in capabilityThread
, so worker1
and worker2
will be created and live in capabilityThread
.
Notice that if you want to access data from another thread not by signal-slot mechanism, you need to use syncronisation (QMutex
) (like in capability->getOtherWorker()
).
You can validate all your assumptions about what runs where using qDebug() << QThread::currentThreadId();
such that the rest of the application can largely ignore what thread it may (or may not) live in
It will only work if you do every data access using signal-slot mechanism (request data, send data). Otherwise you need syncronisation.
Take a look at Qt Concurrent. It has some nice high level multithreading primitives (QFuture
, QPromise
, map-reduce, and thread pool).
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744789183a4593809.html
SIGNAL
andSLOT
macros. They are left over from Qt4 and can hide important problems until runtime. – Botje Commented Mar 11 at 14:24doWork()
method? When you move that object to another thread, the event processing of that object will move to the new thread - but if there will be no events, nothing would be executed. – zerocukor287 Commented Mar 11 at 15:20doWork()
method at all. Basically just place the object in the thread and not have a dedicated piece of work to do, waiting for any slots to be triggered and leaving those to execute in the thread (provided they are connected properly of course) – cancech Commented Mar 11 at 15:24