| Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date | |
| All threads index page 1 | |
The Qt thread documentation has this warning:
> The child of a QObject must always be created in the thread where
>the parent was created. This implies, among other things, that
>you should never pass the QThread object (this) as the parent of
>an object created in the thread (since the QThread object itself
>was created in another thread).
However, I'm finding it hard to figure out exactly what it's
trying to say. I guess that it means that you shouldn't, for
example, create a GUI widget with a parent of "this" inside
a run() method:
void run()
{
QLabel *l = new QLabel("Hello", this); // bad ?
}
but it also seems to imply that you shouldn't create a
thread in a sub-thread with a parent of "this" i.e.
if we have the following in the run() method of a thread
created in main():
void run()
{
QThread *child = new MyThreadClass(this); // bad ?
}
then that is forbidden since the "this" pointer was
created in main().
However, if I've understood this properly, then it also
breaks the QObject parent-child cleanup mechanism, since
it would forbid the creation of a heirarchy of parent-child
threads, which seems, on the other hand, to be explicitly
allowed by the presence of the parent pointer in the QThread
constructor.
Could someone explain this ? There seems to be a discrepancy
(probably in my understanding)
--
[ signature omitted ]
Hi Stephen,
Main thread calls new QThread:
QThread object created in main thread.
QThread constructor call in main thread.
Members created in the constructor are also created in the
main thread.
Do NOT create members that have to be created within the
thread!
QThread parent set to main thread owner.
QThread object now created, but thread has not started executing
yet.
Main thread calls QThread::start
QThread run() starts executing
QThread "this" points to object created in main thread.
try new QObject(this)
fails because "this" was not created within the (sub)
thread's context.
Hence the advice about using automatic allocation:
Use automatic storage to create thread specific objects.
Set them into the QThread members using pointers.
So that member routines have access to them.
Do thread's work...
Main thread calls QThread::wait
main thread loops processing events
QThread run() eventually does its work.
run then clears the thread specific member's pointers.
Exit the run routine.
Main thread stops looping:
Main thread destroys QThread object directly - or indirectly via
owner.
QThread destructor is OK because "this" was created within main
thread.
So if you assign an owner to the QThread, then the owner is also responsible
for waiting on the thread before its destructor finishes.
Hope that helps.
Tony Rietwyk.
> -----Original Message-----
> From: Stephen Collyer [mailto:scollyer@xxxxxxxxxxxxxxxx]
> Sent: Saturday, 1 December 2007 22:23
> To: Qt Interest List
> Subject: QObject reentrancy restriction and QObject cleanup
>
>
> The Qt thread documentation has this warning:
>
> > The child of a QObject must always be created in the thread where
> >the parent was created. This implies, among other things, that
> >you should never pass the QThread object (this) as the parent of
> >an object created in the thread (since the QThread object itself
> >was created in another thread).
>
> However, I'm finding it hard to figure out exactly what it's
> trying to say. I guess that it means that you shouldn't, for
> example, create a GUI widget with a parent of "this" inside
> a run() method:
>
> void run()
> {
> QLabel *l = new QLabel("Hello", this); // bad ?
>
> }
>
> but it also seems to imply that you shouldn't create a
> thread in a sub-thread with a parent of "this" i.e.
> if we have the following in the run() method of a thread
> created in main():
>
> void run()
> {
> QThread *child = new MyThreadClass(this); // bad ?
>
> }
>
> then that is forbidden since the "this" pointer was
> created in main().
>
> However, if I've understood this properly, then it also
> breaks the QObject parent-child cleanup mechanism, since
> it would forbid the creation of a heirarchy of parent-child
> threads, which seems, on the other hand, to be explicitly
> allowed by the presence of the parent pointer in the QThread
> constructor.
>
> Could someone explain this ? There seems to be a discrepancy
> (probably in my understanding)
>
> --
> Regards
>
> Steve Collyer
> Netspinner Ltd
--
[ signature omitted ]
Tony Rietwyk wrote: > Hi Stephen, > > Main thread calls new QThread: > QThread object created in main thread. > QThread constructor call in main thread. > Members created in the constructor are also created in the > main thread. > Do NOT create members that have to be created within the > thread! I don't understand what this last sentence is trying to say. > QThread parent set to main thread owner. How ? You mean via the initialization list ? > QThread object now created, but thread has not started executing > yet. > > Main thread calls QThread::start > > QThread run() starts executing > QThread "this" points to object created in main thread. > try new QObject(this) > fails because "this" was not created within the (sub) > thread's context. I'm not sure what you mean here. How does it fail ? Throws an exception ? Is that what the "try" is for ? > Hence the advice about using automatic allocation: > Use automatic storage to create thread specific objects. Automatic as on stack ? Or am I not understanding what you're saying ? > Set them into the QThread members using pointers. > So that member routines have access to them. I don't know what you mean by "set them into" ? Do you mean assign a pointer variable ? And what are these "QThread members" ? Members of the sub-class of QThread ? > Do thread's work... > > > Main thread calls QThread::wait > main thread loops processing events > > QThread run() eventually does its work. > > run then clears the thread specific member's pointers. What do you mean by "clears the .. pointers" ? Calls "delete" on them ? Sets them to null ? > Exit the run routine. > > Main thread stops looping: > Main thread destroys QThread object directly - or indirectly via > owner. I have no idea what you mean here. > QThread destructor is OK because "this" was created within main > thread. > So if you assign an owner to the QThread, then the owner is also responsible > for waiting on the thread before its destructor finishes. Again, I'm not sure what you mean. For example, does "its destructor" refer to the destructor of the child thread or the owner ? > Hope that helps. Unfortunately not. Maybe it'd be clearer if you wrote some code. -- [ signature omitted ]
On 01.12.07 11:23:06, Stephen Collyer wrote:
> The Qt thread documentation has this warning:
>
> > The child of a QObject must always be created in the thread where
> >the parent was created. This implies, among other things, that
> >you should never pass the QThread object (this) as the parent of
> >an object created in the thread (since the QThread object itself
> >was created in another thread).
>
> However, I'm finding it hard to figure out exactly what it's
> trying to say. I guess that it means that you shouldn't, for
> example, create a GUI widget with a parent of "this" inside
> a run() method:
>
> void run()
> {
> QLabel *l = new QLabel("Hello", this); // bad ?
>
> }
That can never work, GUI elements cannot be created anywhere but the
main thread.
> but it also seems to imply that you shouldn't create a
> thread in a sub-thread with a parent of "this" i.e.
> if we have the following in the run() method of a thread
> created in main():
Right.
> void run()
> {
> QThread *child = new MyThreadClass(this); // bad ?
>
> }
>
> then that is forbidden since the "this" pointer was
> created in main().
Exactly.
> However, if I've understood this properly, then it also
> breaks the QObject parent-child cleanup mechanism, since
> it would forbid the creation of a heirarchy of parent-child
> threads, which seems, on the other hand, to be explicitly
> allowed by the presence of the parent pointer in the QThread
> constructor.
Right. If you create threads in the run() method of another thread, you
have to find an QObject that lives in this thread (i.e. the one that
currently executes the run() method) to use as parent or use no parent
at all and clean up the memory for the new thread yourself.
> Could someone explain this ? There seems to be a discrepancy
> (probably in my understanding)
No there's no discrepancy. Its just a limitation of the
cleanup-mechanism. Either you have all your QObjects that create a
parent/child relationship live in the same thread or you have to do the
cleanup yourself.
Also note: Its not a problem at all to have multiple qobject-tree's
around, thats usually already happening in a program with multiple
toplevel windows. QObject hierarchies are often build between instances
that really do have a parent/child relationship (for example a QGroupBox
and its content widgets)
Andreas
--
[ signature omitted ]
Andreas Pakulat wrote:
>>
>> void run()
>> {
>> QLabel *l = new QLabel("Hello", this); // bad ?
>>
>> }
>
> That can never work, GUI elements cannot be created anywhere but the
> main thread.
Oops ! Good point. I chose a poor example.
>> However, if I've understood this properly, then it also
>> breaks the QObject parent-child cleanup mechanism, since
>> it would forbid the creation of a heirarchy of parent-child
>> threads, which seems, on the other hand, to be explicitly
>> allowed by the presence of the parent pointer in the QThread
>> constructor.
>
> Right. If you create threads in the run() method of another thread, you
> have to find an QObject that lives in this thread (i.e. the one that
> currently executes the run() method) to use as parent or use no parent
> at all and clean up the memory for the new thread yourself.
Or ... presumably you could ensure that you pass an appropriate
QObject pointer all the way down the tree from main() and
reparent the lower level QThreads using QOject::setParent() ?
Would that work ?
--
[ signature omitted ]
Stephen Collyer wrote: >Or ... presumably you could ensure that you pass an appropriate >QObject pointer all the way down the tree from main() and >reparent the lower level QThreads using QOject::setParent() ? All objects in a QObject tree must live in the same thread. You cannot setParent(obj) if obj lives in a different thread. By the same token, you cannot moveToThread() an object that has a parent. -- [ signature omitted ]
Attachment:
signature.asc
Description: This is a digitally signed message part.
Thiago Macieira wrote: > Stephen Collyer wrote: >> Or ... presumably you could ensure that you pass an appropriate >> QObject pointer all the way down the tree from main() and >> reparent the lower level QThreads using QOject::setParent() ? > > All objects in a QObject tree must live in the same thread. You cannot > setParent(obj) if obj lives in a different thread. By the same token, you > cannot moveToThread() an object that has a parent. OK. I'll forget that approach then. -- [ signature omitted ]
On 01.12.07 18:45:22, Thiago Macieira wrote:
> Stephen Collyer wrote:
> >Or ... presumably you could ensure that you pass an appropriate
> >QObject pointer all the way down the tree from main() and
> >reparent the lower level QThreads using QOject::setParent() ?
>
> All objects in a QObject tree must live in the same thread. You cannot
> setParent(obj) if obj lives in a different thread. By the same token, you
> cannot moveToThread() an object that has a parent.
But doesn't that mean that the following would work:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QObject* parent) : QThread(parent), m_parent(parent) {}
void run()
{
MyThread* subthread = new MyThread(0);
subthread->moveToThread( m_parent->thread() );
subthread->setParent( m_parent );
subthread->start();
}
private:
QObject* m_parent;
};
main()
{
QObject* o = new QObject();
MyThread m = new MyThread(o);
}
So Stephen's idea would work, as long as he makes sure to not pass a
parent pointer to the new thread instance and use moveToThread and
setParent as shown in the run() method.
Andreas
--
[ signature omitted ]