Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-interest Archive, December 2007
Re: parent arg for QThread constructor ?

Pages: Prev | 1 | 2 | Next

Message 1 in thread

Andreas Pakulat wrote:
> On 30.11.07 18:56:00, Stephen Collyer wrote:
>> The constructor for QThread looks like this:
>>
>> QThread( QObject * parent = 0 )
>>
>> However, I can't see anything that explains the role of
>> the parent object in the documentation. Can someone explain
>> when a QThread needs, and does not need, the parent argument ?
> 
> Thats just the standard QObject-parent, i.e. to create a QObject-object
> hierarchy. QThread doesn't need that argument, unless you'd like to
> avoid having to care yourself about deletion of the thread.

Right. That's pretty obvious now you've pointed it out. I guess
then that a common approach with Qt threads is to new() each thread,
attaching it to the parent, and allowing the Qt kernel to clean up
thread memory, so you get a thread heirarchy like this:

main thread
--Level one thread
---- Level two thread
------ Level three thread
---- Level two thread
---Level one thread

where threads in level N are owned by the QObject that created
it in level N-1

However, that raises the question of precisely when the cleanup
occurs. I guess that it occurs when the parent has called wait()
on its child, so that un-wait()'ed for threads are never cleaned up ?

-- 
 [ signature omitted ] 

Message 2 in thread

On Saturday 01 December 2007, Stephen Collyer wrote:
> Andreas Pakulat wrote:
> > On 30.11.07 18:56:00, Stephen Collyer wrote:
> >> The constructor for QThread looks like this:
> >>
> >> QThread( QObject * parent = 0 )
> >>
> >> However, I can't see anything that explains the role of
> >> the parent object in the documentation. Can someone explain
> >> when a QThread needs, and does not need, the parent argument ?
> >
> > Thats just the standard QObject-parent, i.e. to create a QObject-object
> > hierarchy. QThread doesn't need that argument, unless you'd like to
> > avoid having to care yourself about deletion of the thread.
>
> Right. That's pretty obvious now you've pointed it out. I guess
> then that a common approach with Qt threads is to new() each thread,
> attaching it to the parent, and allowing the Qt kernel to clean up
> thread memory, so you get a thread heirarchy like this:
>
> main thread
> --Level one thread
> ---- Level two thread
> ------ Level three thread
> ---- Level two thread
> ---Level one thread
>
> where threads in level N are owned by the QObject that created
> it in level N-1
>
> However, that raises the question of precisely when the cleanup
> occurs. I guess that it occurs when the parent has called wait()
> on its child, so that un-wait()'ed for threads are never cleaned up ?

<quote from docs>
QThread::~QThread ()
Destroys the thread.
Note that deleting a QThread object will not stop the execution of the thread 
it represents. Deleting a running QThread (i.e. isFinished() returns false) 
will probably result in a program crash. You can wait() on a thread to make 
sure that it has finished.
</quote>

So i guess un-wait()`ed  threads will not be very application friendly. 

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 3 in thread

Stephen Collyer wrote:
>However, that raises the question of precisely when the cleanup
>occurs. I guess that it occurs when the parent has called wait()
>on its child, so that un-wait()'ed for threads are never cleaned up ?

Like any other QObject, a child object is deleted when the parent is 
deleted.

In your scenario, your level N QThread objects will be deleted when the 
level N-1 objects are deleted.

But mind the docs that Iulian posted: deleting a QThread object will not 
kill the thread and will probably crash the program.
-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 4 in thread

Thiago Macieira wrote:
> Stephen Collyer wrote:
>> However, that raises the question of precisely when the cleanup
>> occurs. I guess that it occurs when the parent has called wait()
>> on its child, so that un-wait()'ed for threads are never cleaned up ?
> 
> Like any other QObject, a child object is deleted when the parent is 
> deleted.

OK.

> In your scenario, your level N QThread objects will be deleted when the 
> level N-1 objects are deleted.

OK.

> But mind the docs that Iulian posted: deleting a QThread object will not 
> kill the thread and will probably crash the program.

I assume that you mean "deleting a QThread object, where its parent
has not called and returned from wait(), will not kill the thread .."

i.e. you must call wait() then delete() ?

However, I'm now rather more concerned about this apparent
discrepancy I pointed out in the other thread I started:
that the QObject parenting rules seem to clash with the
QThread parenting rules.

-- 
 [ signature omitted ] 

Message 5 in thread

Stephen Collyer wrote:
>However, I'm now rather more concerned about this apparent
>discrepancy I pointed out in the other thread I started:
>that the QObject parenting rules seem to clash with the
>QThread parenting rules.

There's no such thing as "QThread parenting rules".

The rules for QObject parenting are very clear: all objects in a tree must 
belong to the same thread. You cannot setParent to an object in a 
different thread and you cannot moveToThread an object that has a parent.

QThread is just another QObject.

The caveat is that the QThread does not belong to its thread: it belongs 
to the thread where it was created.
-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 6 in thread

Thiago Macieira wrote:
> Stephen Collyer wrote:
>> However, I'm now rather more concerned about this apparent
>> discrepancy I pointed out in the other thread I started:
>> that the QObject parenting rules seem to clash with the
>> QThread parenting rules.
> 
> There's no such thing as "QThread parenting rules".

I'm referring to  this:

> 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).

The problem that this seems to engender is this: suppose I create a
thread in main:

int main(..)
{
   MyThread *parent = new MyThread();

   parent->start();
}

Now suppose in the run() method of t, I create a subthread:

void run()
{
   MyThread *child = new MyThread(<some parent>);
}

Now if I wanted to create a tree of QObjects, to ensure Qt performs
the deletions on my behalf, I would want the <some parent> argument
to be the this pointer. But the "rule" (condition, caveat, whatever)
quoted above disallows that, as the child object was not created in
the same thread as the parent object.

So I don't see how one can set up a tree of new()'ed QObjects that
happen to be QThreads, due to this restriction. The quote above
makes it clear that the parent pointer can't be the this pointer,
but unfortunately, it doesn't suggest what it should be.

-- 
 [ signature omitted ] 

Message 7 in thread

Stephen Collyer wrote:
>So I don't see how one can set up a tree of new()'ed QObjects that
>happen to be QThreads, due to this restriction. The quote above
>makes it clear that the parent pointer can't be the this pointer,
>but unfortunately, it doesn't suggest what it should be.

It doesn't have to be anything. It can be anything you want, including 
nothing.

If you don't set a parent, you just have to remember to delete the object 
when you no longer need it.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 8 in thread

Thiago Macieira wrote:
> Stephen Collyer wrote:
>> So I don't see how one can set up a tree of new()'ed QObjects that
>> happen to be QThreads, due to this restriction. The quote above
>> makes it clear that the parent pointer can't be the this pointer,
>> but unfortunately, it doesn't suggest what it should be.
> 
> It doesn't have to be anything. It can be anything you want, including 
> nothing.
> 
> If you don't set a parent, you just have to remember to delete the object 
> when you no longer need it.

Right. But I would guess that the QThread constructor takes a parent
pointer precisely so that QThreads can participate in the QObject
deletion mechanism, else what is there for ?

Let me ask the question in another way: can someone show me sample
code that creates a tree of QThreads that are automatically deleted
by the Qt kernel, via the parent-child QObject mechanism ?

-- 
 [ signature omitted ] 

Message 9 in thread

On 01.12.07 16:18:10, Stephen Collyer wrote:
> Thiago Macieira wrote:
> > Stephen Collyer wrote:
> >> So I don't see how one can set up a tree of new()'ed QObjects that
> >> happen to be QThreads, due to this restriction. The quote above
> >> makes it clear that the parent pointer can't be the this pointer,
> >> but unfortunately, it doesn't suggest what it should be.
> > 
> > It doesn't have to be anything. It can be anything you want, including 
> > nothing.
> > 
> > If you don't set a parent, you just have to remember to delete the object 
> > when you no longer need it.
> 
> Right. But I would guess that the QThread constructor takes a parent
> pointer precisely so that QThreads can participate in the QObject
> deletion mechanism, else what is there for ?

Its just to be able to use the auto-deletion when your supposed parent
object and the QThread object happen to live in the same thread. You
don't have to set that parent and if you create the qthread in a
different thread than the supposed parent lives in you simply can't give
a parent object and of course then you need to handle deletion of that
new qthread yourself.

> Let me ask the question in another way: can someone show me sample
> code that creates a tree of QThreads that are automatically deleted
> by the Qt kernel, via the parent-child QObject mechanism ?

Thats only possible if that tree is created in the same thread, i.e.
none of the tree nodes is created in the run() method of a QThread
class. Thats simply not possible.

Andreas

-- 
 [ signature omitted ] 

Message 10 in thread

Andreas Pakulat wrote:

>> Let me ask the question in another way: can someone show me sample
>> code that creates a tree of QThreads that are automatically deleted
>> by the Qt kernel, via the parent-child QObject mechanism ?
> 
> Thats only possible if that tree is created in the same thread, i.e.
> none of the tree nodes is created in the run() method of a QThread
> class. Thats simply not possible.

Ok, thanks. I was coming to that conclusion. Thanks for confirming
it. It's not a problem in my case. I was merely assuming that it
could be done, due to the provision of the parent arg in the
constructor.

-- 
 [ signature omitted ] 

Message 11 in thread

On Saturday 01 December 2007, Stephen Collyer wrote:
> Let me ask the question in another way: can someone show me sample
> code that creates a tree of QThreads that are automatically deleted
> by the Qt kernel, via the parent-child QObject mechanism ?

Maybe a thread pool class that inherits QObject and acts as a parent for a 
list of QThread classes. Still ... this class would have to stop/wait in the 
destructor for the active threads to finish. 

I guess that the parent parameter of QThread's constructor is more for 
consistency across QObject classes.
 

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 12 in thread

On Saturday 01 December 2007, Stephen Collyer wrote:
[snip]
>
> The problem that this seems to engender is this: suppose I create a
> thread in main:
>
> int main(..)
> {
>    MyThread *parent = new MyThread();
>
>    parent->start();
> }
>
> Now suppose in the run() method of t, I create a subthread:
>
> void run()
> {
>    MyThread *child = new MyThread(<some parent>);
> }
>
> Now if I wanted to create a tree of QObjects, to ensure Qt performs
> the deletions on my behalf, I would want the <some parent> argument
> to be the this pointer. But the "rule" (condition, caveat, whatever)
> quoted above disallows that, as the child object was not created in
> the same thread as the parent object.

To ensure proper destruction of thread objects ( even when an exception is 
thrown ) you could (read should) declare the thread object on the stack. This 
will ensure the destructor of the thread class is called. 

you could do something like this:

void run()
{
	MyThread child;
	child.start();
}

The same goes for the parent thread in main().

>
> So I don't see how one can set up a tree of new()'ed QObjects that
> happen to be QThreads, due to this restriction. The quote above
> makes it clear that the parent pointer can't be the this pointer,
> but unfortunately, it doesn't suggest what it should be.

Out of curiosity why would you ever need a tree-like structure of threads ?


-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 13 in thread

On 01.12.07 18:24:58, Iulian M wrote:
> On Saturday 01 December 2007, Stephen Collyer wrote:
> > Now if I wanted to create a tree of QObjects, to ensure Qt performs
> > the deletions on my behalf, I would want the <some parent> argument
> > to be the this pointer. But the "rule" (condition, caveat, whatever)
> > quoted above disallows that, as the child object was not created in
> > the same thread as the parent object.
> 
> To ensure proper destruction of thread objects ( even when an exception is 
> thrown ) you could (read should) declare the thread object on the stack. This 
> will ensure the destructor of the thread class is called. 
> 
> you could do something like this:
> 
> void run()
> {
> 	MyThread child;
> 	child.start();
> }

I'm no thread guru, but doesn't this crash the app, exactly because of
what has been said in this thread? child will be deleted when run() is
done, however the thread of child might not be finished at that point
and thus you'll get a crash.

Andreas

-- 
 [ signature omitted ] 

Message 14 in thread

On Saturday 01 December 2007, Andreas Pakulat wrote:
> On 01.12.07 18:24:58, Iulian M wrote:
> > On Saturday 01 December 2007, Stephen Collyer wrote:
> > > Now if I wanted to create a tree of QObjects, to ensure Qt performs
> > > the deletions on my behalf, I would want the <some parent> argument
> > > to be the this pointer. But the "rule" (condition, caveat, whatever)
> > > quoted above disallows that, as the child object was not created in
> > > the same thread as the parent object.
> >
> > To ensure proper destruction of thread objects ( even when an exception
> > is thrown ) you could (read should) declare the thread object on the
> > stack. This will ensure the destructor of the thread class is called.
> >
> > you could do something like this:
> >
> > void run()
> > {
> > 	MyThread child;
> > 	child.start();
> > }
>
> I'm no thread guru, but doesn't this crash the app, exactly because of
> what has been said in this thread? child will be deleted when run() is
> done, however the thread of child might not be finished at that point
> and thus you'll get a crash.
>
> Andreas

Yes, you are rigth. It was meant only as an example of starting a "subthread".  
It sould go like this:

void run()
{
	MyThread child;
	child.start();

	... do other stuff in this thread and child.wait() for child to finish ... 
	... or if you need an event loop start it by using exec() 

	... before returning form the function make sure child.isFinished() returns 
true.
}



-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 15 in thread

Iulian M wrote:

> Out of curiosity why would you ever need a tree-like structure of threads ?

There are several reasons:

1. Practical - I'm porting some code to Qt that already has a
tree-like structure of processes and that will map most cleanly
onto a tree-like structure of threads.

2. Theoretical - if you can't have a tree-like structure of threads,
you can only run single threaded code, since a Parent-Child structure
is already a tree. And if you allow Parent-Child, why should you
disallow Parent-Child-Child ?

3. Pragmatic - you've got it whether you like it or not, as Qt
allows it (as do other thread systems)

4. Good design - if you spawn a thread to do a job, good
engineering practice demands that it be a black box - you
should neither know nor care if it spawns sub-threads to
do its job.

Finally, it's a common approach anyway - regardless of
whether we "need" it in any absolute sense, plenty of systems
spawn threads, and sub-threads, and sub-threads as it's
such a natural thing to do - note that any Unix box runs a large
tree of processes. It'd be hard to design a moderately complex
system if it were disallowed.

This is off-topic though.

-- 
 [ signature omitted ] 

Pages: Prev | 1 | 2 | Next