I would like to know what difference there is between new QThread(this) and new QThread() and how this would influence the behaviour of my code when using QThread.
The parent of a QThread does not make any difference on who executes what.
It is just the classic parent-child relationship in Qt, the Object-Tree, meaning the parent takes ownership of the QThread instance and will delete its child when it gets deleted.
What is important when it comes to threads in Qt is
Where do you create a QObject instance (by default the object belongs to the thread that created it)
The parent of a QObject instance (when you do a QObject::moveToThread(QThread *targetThread) all the children of the object are moved too)
Because : the slots of a QObject are executed in the thread that it belongs to.
Related
I have done something like this:
//in the mainwindow's constructor
QThread *thr = new QThread;
soundWorker * work = new soundWorker;
connect(this,SIGNAL(playsound()),work,SLOT(process()));
work->moveToThread(thr);
thr->start();
Shall I delete thr and work at the deconstructor of mainwindow?
You can use the default Qt way of managing memory by assigning a parent to the QThread, i.e. do this:
QThread *thr = new QThread(this);//the mainwindow's is now the thread parent
In Qt, parents are responsible for managing the memory of their children. Thus, the QThread will be automatically deleted when needed.
Then, for your soundWorker, you have a few different solutions. If its lifetime is the same as your mainwindow, as you hint when you ask if you should delete it in the destructor of the mainwindow, you could simply make it a non-pointer member, and its storage duration would then become automatically handled.
The parent thing is specific to Qt though. In general, when you deal with memory yourself, you should resort to wrappers (such as smart pointers) that enables RAII.
Further reading: Qt Trees and ownership model
You can use the QThread::finished() signal in order detect the moment you wish to release the QThread pointer. Same thing could be done with QObject pointers which were moved to the new thread.
Considering that the moment of closing the main window is the moment of closing the whole application and considering that you don't need to further do processing after the application was closed, you can pass the main window pointer as a parent to the QThread by either passing it to the constructor or using QObject::setParent.
Releasing the resources acquired inside the thread handled by QThread must be handled separately as you can't make the QThread object a parent of a resource managed by it - QThread lives in the thread where it was created and not in the thread it manages.
More details here.
Say I have created a QObject a and it has a member QObject b. (Actually, both A and B are subclasses of QObject, and class A has a member B b.)
When b is created, its parent is 0 (default). In the code, if I never set b's parent to a, and if I call movetothread() to move a into a worker thread, will b be moved into that thread too?
If it is not moved, if I call b.init() from the worker thread (the one I moved a into) which use new operator to create another QObject that has b as a parent, then I will get the following error, right?
QObject: Cannot create children for a parent that is in a different thread
As the Qt documentation for QObject::moveToThread states: -
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
In this case, a parent is an object whose child is set either by passing the parent in the constructor or by calling setParent on the child. It is not an an object which has a pointer to another object.
In the code, if I never set b's parent to a, and if I call movetothread() to move a into a worker thread, will b be moved into that thread too?
So, no, if b's parent is not set and you call moveToThread on 'a', 'b' will still have the original thread affinity.
If it is not moved, if I call b.init() from the worker thread...
If you've moved 'a' and not 'b' to a worker thread, then you should not be calling b.init directly from the worker thread. Instead, the object in the worker thread ('a') should emit a signal for an object in the original thread to call b.init from a connected slot
will b be moved into that thread too?
No, QObject doesn't know that b is a member of a. (You didn't say whether a holds a pointer to b or whether it holds b directly, but the answer is the same in both cases.)
then I will get the following error, right?
The child of a QObject must always be created in the thread which owns the parent. I'm reluctant to say that you will definitely get an error, because the behaviour may be undefined.
See Threads and QObject.
I have a question concerning the Slot-/Signal-architecture in Qt. For my project I have separate functions for:
a) GUI
b) controlling external devices
Now I want to have function b) constantly listening to Signals sent from a) on specific slots. But this listening should not influence the GUI thread, e.g. I want to continue with my work there.
Thus I had the idea to move the function b) to a separate thread. But my problem is that I do not know how to create the run-function in this thread. It should start with my program (no problem), and it should constantly listen to incoming signals and then run the function which is connected to this signal.
Would a simple while(1) be enough?
Qt makes this pretty straightforward. I would not advise overriding run() for this as it is not necessary - also it is not as flexible or easy to implement, and has a few caveats regarding object creation.
Instead, just create a thread then move your listening object to it. For example:
// 'this' as parent means thread will terminate automatically when 'this'
// is deleted, you have other options here, of course.
QThread *thread = new QThread(this);
// Create your object (or just use an existing one). Note new object initially
// lives on current thread. Note also it does not have a parent. Objects with
// parents cannot be moved to other threads explicitly.
MyObject *object = new MyObject(); // Assuming MyObject is a QObject.
// Now move the object to the new thread.
object->moveToThread(thread);
// And, you'll want to make sure the object is deleted when the thread ends.
connect(thread, SIGNAL(finished()), object, SLOT(deleteLater()));
connect(thread, SIGNAL(terminated()), object, SLOT(deleteLater())); // just in case
// Finally, start the thread:
thread->start();
That's all you need to do! Now the thread is running, with its own event loop, and signals connected to the object's slots will be queued and run on that thread†.
Note that if your object's constructor creates any QObjects of its own, it should set itself as those objects' parent accordingly. Qt will automatically move all child objects of your object to the thread as well when you do object->moveToThread().
You can move as many objects as you want to a given QThread, it isn't limited to just one.
To explicitly end the thread, and clean up the object, call thread->exit() or just delete the thread. Again, though, since we made this a parent of the QThread in the above example, you really don't need to do any cleanup at all.
By the way, if you have some initialization or other tasks that your object should perform on the thread when the thread is started, you can also use the thread's started() signal:
connect(thread, SIGNAL(started()), object, SLOT(initializeWhatever()));
Note, of course, that any objects used in the above way must be subclasses of QObject. This is where e.g. moveToThread() and deleteLater() are, and is also required for proper handling of slots:
class MyObject : public QObject {
Q_OBJECT
public:
MyObject (QObject *parent = 0);
signals:
...
public slots:
...
};
The easiest way, really, to set this up is in QtCreator, right click, add a new class, and choose QObject as a base there. Qt will set up a template header and source file for you.
† Unless the connection type is DirectConnection, but by default it is not.
My application uses a custom serialization mechanism.
Phase 1) The mechanism loads clusters of data on a separate thread, creates all appropriate objects there and so on.
Phase 2) Once they are all fully deserialized, it hands them over to the main application thread and finishes the serialization there by for example setting up connections between objects etc.
This mechanism is a new addition to my framework – before that I was deserializing everything on the main thread.
The problem I have is that some of the objects that are created during deserializatiuon are Qt objects ( a bunch of widgets basically ).
They all record the ids of a thread they were created on. And when the time comes for “phase 2”, these objects start complaing that they all don’t belong to this thread and therefore can have no signals sent etc.
So I found a method on QObject, called ‘moveToThread’. The little bugger’s not very helpful though, as it performs a check and prevents from moving objects from a different thread to the current thread ( WHY scuh a constraint, I have no clue ).
Does anyone have an idea how can I go about this? I can guarantee that the objects will only be createad on a separate thread, and from that point on they will all be living and operating on the main thread.
Thanks,
Paksas
Instances of a QObject, or any instance of subclasses of QObjects must be handled with care when it comes to multi-threading.
Take a look to this page for an introduction to the topic.
Suppose that your application consists of two threads A and B.
Suppose that thread A creates an object QObject instance.
instance is said to live in thread A. This means that:
- it can directly send and receive signals to all other objects living in thread A.
- all calls done to method of myInstance from thread A are thread-safe
Accessing instance from the other thread B, on the other hand:
- is not thread safe (you must take care of race conditions).
- Moreover signals emitted by instance and connected to slot of objects in thread B are not direct: the slot execution is deferred to a later moment by copying all the method parameters and placing everything in an event to be executed by thread B event queue.
Given this, the solution that you can exploit is the following.
SubClass is a subclass of a QObject.
class SubClass : public QObject{
Q_OBJECT
[...]
}
The thread A will run the following method to deserialize and populate memory with SubClass instances
void methodA(){ /this method is executed by thread A
QThread* threadB; //a reference to the QThread related to thread B
[...]
MyQObject* instance = someFactoryMethod();
//we push the ownership of instance from thrad A to thread B
instance->moveToThread( threadB );
//do something else
}
Notice however that this might not be sufficient if thread A needs to perform other operations on instance. In particular it might happens that thread A will trigger some singals defined in MyQObject. This is not allowed since now thread A is not the owner of instance anymore.
In this case you need to defer such operation and ask thread B to perform it. This is realized by using the QMetaObject::invokeLater method.
InvokeLater allows you to call a specific slot asking thread B to execute it.
Suppose that ClassInB is a class whose instances are used in thread B
class ClassInB : public QObject{
Q_OBJECT
public:
[...]
slots:
void complexOperation(MyQObject* o){
[...]
emitSomeSignal();
}
signals:
void someSignal();
}
after moving instance to thread B we need to execute complexOperation() on an instance of ClassInB living in thread B which, in turn, will also emit someSignal().
void methodA(){ //this method is executed by thread A
QThread* threadB; //a reference to the QThread related to thread B
ClassInB* instanceOnB; //a reference to a ClassInB instance living in thread B
[...]
MyQObject* instance = someFactoryMethod();
//we push the ownership of instance from thread A to thread B
instance->moveToThread( threadB );
//we ask thread B to perform some operation related to instance
QMetaObject::invokeLater(instanceOnB, "complexOperation", Q_ARG(MyQObject*, instance) );
}
To be able to use MyQObject* as a parameter of invokeLater we need to register it to the Meta framework. You will need to:
add Q_DECLARE_METATYPE(MyQObject*) in the .cpp defining MyQObject
call once, before using the mechanism (e.g. in the main), qRegisterMetaType<MyQObject*>();
Simply replace your function calls with QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method) to run a slot in another thread, since according to documentation, it executes the slot from the target thread.
This way you don't need to bother with changing your code in any way, or wondering if your current object is in the same thread or not, etc.
What are the lifetimes of Qt Objects?
Such as:
QTcpSocket *socket=new QTcpSocket();
When socket will be destroyed? Should I use
delete socket;
Is there any difference with:
QTcpSocket socket;
I couldn't find deep infromation about this, any comment or link is welcomed.
Qt uses parent-child relationships to manage memory. If you provide the QTcpSocket object with a parent when you create it, the parent will take care of cleaning it up. The parent can be, for example, the GUI window that uses the socket. Once the window dies (i.e. is closed) the socket dies.
You can do without the parent but then indeed you have to delete the object manually.
Personally I recommend sticking to idiomatic Qt and using linking all objects into parent-child trees.
Objects allocated with new must be released with delete.
However, with Qt, most objects can have a parent, which you specify as an argument to the constructor. When the parent is deleted, the child objects get deleted automatically.
If you don't want to pass a parent for some reason (because there is no QObject where it makes sense to own the socket object), you can also use a QSharedPointer to manage the lifetime.