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

Qt-interest Archive, December 2006
Threads, signals etc.

Pages: Prev | 1 | 2 | Next

Message 1 in thread

Hallo,

I got problems w/signal delivery in threads. It seems I do not 
understand completely what is going on. May be someone could
have a look over the attached example?

Basically it should implement a worker thread, which gets jobs thrown at 
and executes these in order. The example job implemented here should 
count down a number of times, everytime saying ping(), and after that 
emit the completed() signal.

However, the ping() slot never gets called. I don't know if it's the 
timer not activated for some reason, or if it's the thread's event loop 
not delivering the signal.

Could someone look that over, please? (Any other comments on my approach 
are welcome, too :-)

Thanks,
/eno

#include "worker.h"
#include "worker.h"
#include <QCoreApplication>
	

// extern "C" 
int main(int argc, char** argv)
{
	QCoreApplication app(argc, argv);

	worker w;
	w.start();
	w.sendJob(new countdown(5));
	w.wait();

	return 0;
}

#ifndef WORKER_H
#ifndef WORKER_H
#define WORKER_H

#include <QThread>
#include <QTimer>

#include <iostream>

class worker;

// A base class for a job.
class job: public QObject {
	Q_OBJECT

	friend class worker;
	
public:
	//! execute the job
	/*!
	 * This method starts the job.
	 * When done the completed() or failed() signal must
	 * be emitted.
	 */
	virtual void start() = 0;

signals:
	//! This signal is emitted when the job starts.
	void started();
	
	//! This signal is emitted when the job is completed successfully.
	void completed();
	
	//! This signal is emitted when the job is completed w/failure.
	void failed();
};

//! a worker thread
class worker: public QThread {
	Q_OBJECT
	
	QList<job*> jobs_;
	job* activeJob_; 

public:
	worker()
	{ 
		activeJob_ = 0;	
		connect(this, SIGNAL(sendJobSignal(job*)), this, SLOT(onSendJob(job*)));
	}

	void sendJob(job* j)
	{ emit sendJobSignal(j); }
		
protected:
	void run()
	{
		//
		// starts the event loop. The event loop runs until 
		// someone calls quit() or exit().
		//
		exec();
	}


private:
	void activateNextJob()
	{
		std::cout << "activateNextJob()" << std::endl;

		assert(jobs_.size());
	
		job* j = jobs_.front();
		jobs_.pop_front();
	
		//
		// this emits the job's started() signal, to inform everyone that
		// we are now really starting... 
	 	//
		emit j->started();

		connect(j, SIGNAL(completed()), this, SLOT(jobCompleted()));
		connect(j, SIGNAL(failed()), this, SLOT(jobCompleted()));

		try {
			j->start();
		}
		catch(const std::exception& e) {
			emit j->failed();
		}
	}


private slots:
	void onSendJob(job* j)
	{
		jobs_.push_back(j);
		if(activeJob_ == 0) activateNextJob();
	}

	void jobCompleted()
	{
		assert(dynamic_cast<job*>(sender()));
		assert(sender() == activeJob_);
		
		delete activeJob_;					
		activeJob_ = 0;
		
		if(jobs_.size()) activateNextJob();
	}
	
signals:
	// emitted in response to sendJob(job*) and connected to onSendJob...
	void sendJobSignal(job*);
};


class countdown: public job {
	Q_OBJECT 
	
	int cnt_;
	QTimer tm;
	
public:
	countdown(int cnt = 3): cnt_(cnt) 
		{ }
	
	void start()
	{
		connect(&tm, SIGNAL(timeout()), this, SLOT(ping()));
		tm.start(100);
		std::cout << "start()" << std::endl;
	}
	
	
public slots:
	void ping()
	{
		std::cout << "ping()" << std::endl;
		if(--cnt_ < 0)  emit completed();
	}
};

#endif
TEMPLATE=app
TEMPLATE=app
win32:TEMPLATE=vcapp

SOURCES += worker.cpp
HEADERS += worker.h

QT += network


Message 2 in thread

On Monday 11 December 2006 18:25, Enrico Thierbach wrote:
> Could someone look that over, please? (Any other comments on my approach
> are welcome, too :-)

You should read http://doc.trolltech.com/4.2/threads.html. Specifically,
http://doc.trolltech.com/4.2/threads.html#accessing-qobject-subclasses-from-other-threads:

"Like other objects, QThread objects live in the thread where the object was 
created -- not in the thread that is created when QThread::run() is called. 
It is generally unsafe to provide slots in your QThread subclass, unless you 
protect the member variables with a mutex."

and 
http://doc.trolltech.com/4.2/threads.html#signals-and-slots-across-threads:

"With queued connections, the slot is invoked when control returns to the 
event loop of the thread to which the object belongs. The slot is executed in 
the thread where the receiver object lives.

With auto connections (the default), the behavior is the same as with direct 
connections if the signal is emitted in the thread where the receiver lives; 
otherwise, the behavior is that of a queued connection."



What you are seeing is expected behavior. Your QThread subclass belongs to the 
GUI thread, so the GUI thread is supposed to call your slots. But since you 
aren't running an event loop in the GUI thread, none of your slots get 
called.

> Thanks,
> /eno

-- 
 [ signature omitted ] 

Message 3 in thread

Bradley T Hughes wrote:
> On Monday 11 December 2006 18:25, Enrico Thierbach wrote:
>> Could someone look that over, please? (Any other comments on my approach
>> are welcome, too :-)

Thank you, Bardley, for your answer.

The so-called "thread affinity" of Qt4's signal delivery is a wicked 
thing, to say at least.
Now that I found QObject::moveToThread() - which I wasn't aware of - it 
seems I can finally go on w/my workers/jobs thingy.

If I get it right it requires (signal/slot-)active objects that should 
become active within a thread to be created from within the thread's 
run() method, or to be moved to that thread via QObject::moveToThread.
Is that right?

And what is still unclear to me is on an queued connection which 
object's thread's event loop is to be running: the sender's or the 
recipient's.

More experimenting on my side... If anybody wants to see the results 
stay tuned.

/eno

--
 [ signature omitted ] 

Message 4 in thread

On Tuesday 12 December 2006 11:44, Enrico Thierbach wrote:
> Bradley T Hughes wrote:
> > On Monday 11 December 2006 18:25, Enrico Thierbach wrote:
> >> Could someone look that over, please? (Any other comments on my approach
> >> are welcome, too :-)
>
> Thank you, Bardley, for your answer.
>
> The so-called "thread affinity" of Qt4's signal delivery is a wicked
> thing, to say at least.
> Now that I found QObject::moveToThread() - which I wasn't aware of - it
> seems I can finally go on w/my workers/jobs thingy.
>
> If I get it right it requires (signal/slot-)active objects that should
> become active within a thread to be created from within the thread's
> run() method, or to be moved to that thread via QObject::moveToThread.
> Is that right?

Yes, you create the object in the thread you want it to "live" in (or move it 
there with QObject::moveToThread()).

> And what is still unclear to me is on an queued connection which
> object's thread's event loop is to be running: the sender's or the
> recipient's.

The receiver's - signals are immediate since they "signal" (pun intended) when 
something happens. It's the slot that does the work, and as such, gets called 
by the event loop running in the receiver's thread.


-- 
 [ signature omitted ] 

Message 5 in thread

Hi,

I've been working with QThread quite a lot recently.

The clearest way I found was :
- let the MyQThread object leave in the main GUI thread
- for each class MyQThread, systematically create a "utility class" called
MyQThreadInternal, which inherits from QObject.
- in MyQThread::run(), instanciate an object of type MyQThreadInternal and
start the thread event loop
The object MyQThreadInternal alwyas "leaves" in the thread, and the QThread
object still leaves in the GUI thread.

- now, all the work of the thread should be done within MyQThreadInternal


MyQThreadInternal may have various signals and slots, so as MyQThread.

Signal from MyQThreadInternal may be connected to signals of the same name
in MyQThread, or slots (and same the other way). 
Hence, Qt will reemit asyncroneously from MyQThread, within the main GUI
thread, all signal emited within the thread itself, ie from
MyQThreadInternal.

I found this **architecture** the most easy to work with, especially because
all the objects' thread affinity is clear.

In case it helps...
Best-
Nicolas

Bradley T Hughes wrote:

> On Tuesday 12 December 2006 11:44, Enrico Thierbach wrote:
>> Bradley T Hughes wrote:
>> > On Monday 11 December 2006 18:25, Enrico Thierbach wrote:
>> >> Could someone look that over, please? (Any other comments on my
>> >> approach are welcome, too :-)
>>
>> Thank you, Bardley, for your answer.
>>
>> The so-called "thread affinity" of Qt4's signal delivery is a wicked
>> thing, to say at least.
>> Now that I found QObject::moveToThread() - which I wasn't aware of - it
>> seems I can finally go on w/my workers/jobs thingy.
>>
>> If I get it right it requires (signal/slot-)active objects that should
>> become active within a thread to be created from within the thread's
>> run() method, or to be moved to that thread via QObject::moveToThread.
>> Is that right?
> 
> Yes, you create the object in the thread you want it to "live" in (or move
> it there with QObject::moveToThread()).
> 
>> And what is still unclear to me is on an queued connection which
>> object's thread's event loop is to be running: the sender's or the
>> recipient's.
> 
> The receiver's - signals are immediate since they "signal" (pun intended)
> when something happens. It's the slot that does the work, and as such,
> gets called by the event loop running in the receiver's thread.
> 
> 

--
 [ signature omitted ] 

Message 6 in thread

On Wednesday 13 December 2006 09:42, Nicolas Castagne wrote:
> The clearest way I found was :
> - let the MyQThread object leave in the main GUI thread
> - for each class MyQThread, systematically create a "utility class" called
> MyQThreadInternal, which inherits from QObject.
> - in MyQThread::run(), instanciate an object of type MyQThreadInternal and
> start the thread event loop
> The object MyQThreadInternal alwyas "leaves" in the thread, and the QThread
> object still leaves in the GUI thread.
>
> - now, all the work of the thread should be done within MyQThreadInternal
>
>
> MyQThreadInternal may have various signals and slots, so as MyQThread.
>
> Signal from MyQThreadInternal may be connected to signals of the same name
> in MyQThread, or slots (and same the other way).
> Hence, Qt will reemit asyncroneously from MyQThread, within the main GUI
> thread, all signal emited within the thread itself, ie from
> MyQThreadInternal.
>
> I found this **architecture** the most easy to work with, especially
> because all the objects' thread affinity is clear.

This is a very good idea, and it is actually the way I advocate using threads 
in Qt. If everything goes my way, it will become the default way of doing 
things. 

<shameless-plug>
http://blogs.qtdeveloper.net/archives/2006/12/04/threading-without-the-headache/
</shameless-plug>

-- 
 [ signature omitted ] 

Message 7 in thread

Hi,

>> I found this **architecture** the most easy to work with, especially
>> because all the objects' thread affinity is clear.
> 
> This is a very good idea, and it is actually the way I advocate using threads 
> in Qt. If everything goes my way, it will become the default way of doing 
> things. 
> 
> <shameless-plug>
> http://blogs.qtdeveloper.net/archives/2006/12/04/threading-without-the-headache/
> </shameless-plug>
>


While this is similar to what I am doing here meanwhile, one problem 
remains: As, like in your example, the producer and consumer are created 
not-from-the-thread they are supposed to live in, once they get active, 
what happens with that objects, that are no childs of producer/consumer 
respectively?

In short: can an object or a group of objects created outside a thread's 
run() method moved to the thread and activated during the thread's run() 
made behave as excepted, i.e. as they would behave in the context of the 
thread they were created in?

The call to QObject::moveToThread() doesn't do anything to non-related 
objects, their thread affinity remains unchanged. This, in turn, 
requires all objects be managed on the heap, hence code like this:

class A: public QObject
{
	QTimer tm;
	
	A() { connect(&tm, SIGNAL(timeout()), ...); }
};

will never work as expected (And I love creating my QTimer's as static 
class members ;-).

I see only two ways out of here

(0)

/* not applicable */ request all objects, that can be used like you 
propose, to stick to a heap-managed, strictly related policy. I guess, 
it is not applicable as you cannot just take current code, rewrap it a 
bit and send it down the pipe. You cannot know for sure whether or not 
there is an object embedded somewhere which doesn't get a parent or - 
beware - the wrong one (qApp?)

Qt can certainly not warn in all that cases.

(1)

Make moveToThread virtual. In this case moveToThread had to ensure all 
related objects are living in the right thread. Which would work, 
somehow, at least.

(2)

Add automatic thread affinity. Instead of determining thread affinity 
the moment an object is created, the thread affinity could be determined 
the moment, the object is connected from/to for the very first time, 
assuming that the context that happens is the "natural" habitat of the 
object.

Just my two pennies here,
/eno

--
 [ signature omitted ] 

Message 8 in thread

I ma not sure to get everything in your last thread but...

> While this is similar to what I am doing here meanwhile, one problem
> remains: As, like in your example, the producer and consumer are created
> not-from-the-thread they are supposed to live in, once they get active,
> what happens with that objects, that are no childs of producer/consumer
> respectively?

What do you mean by an "active object" ?

And do you use the word "child" as in Qt (QObject::children) ?
Or as "child of a thread" (ie of the thread understood as a "process") ?

If it is the second... Well, I would not say that a QObject is the "child of
the thread", but  that it is "affine with" the thread (or something like
this).

Now, basically, the "thread affinity" of a QObject when it is built is the
thread that is currently executing the constructor. 
Indeed, I am quite sure that the thread affinity is choosen by Qt in
QObject::QObject(...) by calling simply 
        QThread::currentThread()

 
> In short: can an object or a group of objects created outside a thread's
> run() method moved to the thread and activated during the thread's run()
> made behave as excepted, i.e. as they would behave in the context of the
> thread they were created in?

Moved by calling QObject::moveToThread() ?
Then, I guess that all the connection (QObject::connect) to/from the
signal/slots of the object made BEFORE the move will keep their old
ConnectionType.

> The call to QObject::moveToThread() doesn't do anything to non-related
> objects, their thread affinity remains unchanged. This, in turn,
> requires all objects be managed on the heap, hence code like this:
> 
> class A: public QObject
> {
> QTimer tm;
> 
> A() { connect(&tm, SIGNAL(timeout()), ...); }
> };
> 
> will never work as expected (And I love creating my QTimer's as static
> class members ;-).

Mmmhhh... Sure it will work as I would expect :=)

Since QTimer tm  is NOT a class attribute (no "static" keyword), it is
constructed when the instance of A itself is constructed (ie : from the
constructor of A).

Hence, the thread affinity of tm will be the thread affinity of the instance
of A, ie, the thread affinity of BOTH will be the thread that actually
called the constructer. 
No matter A is created on the heap or not.


Hence, for exemple, if in A::A() the timeout signal of tm is connected to a
slot in A, it will be a "direct connection".

And if a signal of another object, created by the main thread, before the
thread was started for example, is connected to a slot in A, it will be a
QueuedConnection : 
the signal will be "posted" to the thread, and the slot will be executed by
the thread's event loop.


You may change this later by calling QObject::moveToThread(). But, of course
changing the thread affinity of the instance of A will not change the
thread affinity of the tm.



Now, I think you may not create QTimer tm as a class object (ie with the
static keyword), because, I think, Qt does not allow you creating QObject
before QApplication is constructed.


Hope it helps !

Nicolas

Enrico Thierbach wrote:

> Hi,
> 
>>> I found this **architecture** the most easy to work with, especially
>>> because all the objects' thread affinity is clear.
>> 
>> This is a very good idea, and it is actually the way I advocate using
>> threads in Qt. If everything goes my way, it will become the default way
>> of doing things.
>> 
>> <shameless-plug>
>>
http://blogs.qtdeveloper.net/archives/2006/12/04/threading-without-the-headache/
>> </shameless-plug>
>>
> 
> 
> While this is similar to what I am doing here meanwhile, one problem
> remains: As, like in your example, the producer and consumer are created
> not-from-the-thread they are supposed to live in, once they get active,
> what happens with that objects, that are no childs of producer/consumer
> respectively?
> 
> In short: can an object or a group of objects created outside a thread's
> run() method moved to the thread and activated during the thread's run()
> made behave as excepted, i.e. as they would behave in the context of the
> thread they were created in?
> 
> The call to QObject::moveToThread() doesn't do anything to non-related
> objects, their thread affinity remains unchanged. This, in turn,
> requires all objects be managed on the heap, hence code like this:
> 
> class A: public QObject
> {
> QTimer tm;
> 
> A() { connect(&tm, SIGNAL(timeout()), ...); }
> };
> 
> will never work as expected (And I love creating my QTimer's as static
> class members ;-).
> 
> I see only two ways out of here
> 
> (0)
> 
> /* not applicable */ request all objects, that can be used like you
> propose, to stick to a heap-managed, strictly related policy. I guess,
> it is not applicable as you cannot just take current code, rewrap it a
> bit and send it down the pipe. You cannot know for sure whether or not
> there is an object embedded somewhere which doesn't get a parent or -
> beware - the wrong one (qApp?)
> 
> Qt can certainly not warn in all that cases.
> 
> (1)
> 
> Make moveToThread virtual. In this case moveToThread had to ensure all
> related objects are living in the right thread. Which would work,
> somehow, at least.
> 
> (2)
> 
> Add automatic thread affinity. Instead of determining thread affinity
> the moment an object is created, the thread affinity could be determined
> the moment, the object is connected from/to for the very first time,
> assuming that the context that happens is the "natural" habitat of the
> object.
> 
> Just my two pennies here,
> /eno
> 
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body. List archive and information:
> http://lists.trolltech.com/qt-interest/

--
 [ signature omitted ] 

Message 9 in thread

Hi,

> Now, I think you may not create QTimer tm as a class object (ie with the
> static keyword), because, I think, Qt does not allow you creating QObject
> before QApplication is constructed.

Generally speaking global static objects are not a good idea because the 
order of instantiation depends on the compiler (some older compilers 
wouldn't even instantiate a static object in some cases).

In a threaded environment, any static variable may cause problems when 
initialized/accessed from two different threads.

--
 [ signature omitted ] 

Message 10 in thread

On Wednesday 13 December 2006 13:20, Enrico Thierbach wrote:
> Hi,
>
> >> I found this **architecture** the most easy to work with, especially
> >> because all the objects' thread affinity is clear.
> >
> > This is a very good idea, and it is actually the way I advocate using
> > threads in Qt. If everything goes my way, it will become the default way
> > of doing things.
> >
> > <shameless-plug>
> > http://blogs.qtdeveloper.net/archives/2006/12/04/threading-without-the-he
> >adache/ </shameless-plug>
>
> While this is similar to what I am doing here meanwhile, one problem
> remains: As, like in your example, the producer and consumer are created
> not-from-the-thread they are supposed to live in, once they get active,
> what happens with that objects, that are no childs of producer/consumer
> respectively?

Then you have to move them yourself (see below).

> In short: can an object or a group of objects created outside a thread's
> run() method moved to the thread and activated during the thread's run()
> made behave as excepted, i.e. as they would behave in the context of the
> thread they were created in?

Yes, that's the whole point of QObject::moveToThread() :)

> The call to QObject::moveToThread() doesn't do anything to non-related
> objects, their thread affinity remains unchanged. This, in turn,
> requires all objects be managed on the heap, hence code like this:
>
> class A: public QObject
> {
> 	QTimer tm;
>
> 	A() { connect(&tm, SIGNAL(timeout()), ...); }
> };
>
> will never work as expected (And I love creating my QTimer's as static
> class members ;-).

As *static* members, or normal members?

> I see only two ways out of here
>
> (0)
>
> /* not applicable */ request all objects, that can be used like you
> propose, to stick to a heap-managed, strictly related policy. I guess,
> it is not applicable as you cannot just take current code, rewrap it a
> bit and send it down the pipe. You cannot know for sure whether or not
> there is an object embedded somewhere which doesn't get a parent or -
> beware - the wrong one (qApp?)

Perhaps I missing something, but if you wrote the code, you should know what 
parent your objects do or don't have :)

> Qt can certainly not warn in all that cases.
>
> (1)
>
> Make moveToThread virtual. In this case moveToThread had to ensure all
> related objects are living in the right thread. Which would work,
> somehow, at least.

You can reimplement QObject::event() and watch for the QEvent::ThreadChange 
event and do whatever you want (like move your static timers...).

> (2)
>
> Add automatic thread affinity. Instead of determining thread affinity
> the moment an object is created, the thread affinity could be determined
> the moment, the object is connected from/to for the very first time,
> assuming that the context that happens is the "natural" habitat of the
> object.

This sounds like a good idea, but doesn't work in practice. People normally do 
things in constructors that would cause the thread affinity to be set (like 
signal/slot connects, starting timers, etc.)

-- 
 [ signature omitted ] 

Message 11 in thread

Hi Bradley,

>> In short: can an object or a group of objects created outside a thread's
>> run() method moved to the thread and activated during the thread's run()
>> made behave as excepted, i.e. as they would behave in the context of the
>> thread they were created in?
> 
> Yes, that's the whole point of QObject::moveToThread() :)

I know. But see below, please.

>> class A: public QObject
>> {
>> 	QTimer tm;
>>
>> 	A() { connect(&tm, SIGNAL(timeout()), ...); }
>> };
>>
>> will never work as expected (And I love creating my QTimer's as static
>> class members ;-).
> 
> As *static* members, or normal members?

As a normal member (See the code :-). I know this is easily worked 
around by

class A: public QObject
{
	
	QTimer* tm;

	A() { tm = new QTimer(this); connect(&tm, SIGNAL(timeout()), ...); }
};

but besides that it costs a bit (an additional allocation on the heap) I 
feel it strange that the latter works while the former cannot.

Note: I am used to use the QObject child/parent-relationship for exactly 
two purposes:

1) Defining a hierarchy of objects
2) Defining ownership of objects

While even this is not-the-best-design-ever (what if the owner of an 
object is not its hierarchical parent, but, say, a list of objects or - 
horror - a shared pointer object of some kind) this gets simply overly 
used by adding additional meaning to it, here how thread affinity is 
determined and how moveToThread() works.

 >>
> 
>> I see only two ways out of here
>>
>> (0)
>>
>> /* not applicable */ request all objects, that can be used like you
>> propose, to stick to a heap-managed, strictly related policy. I guess,
>> it is not applicable as you cannot just take current code, rewrap it a
>> bit and send it down the pipe. You cannot know for sure whether or not
>> there is an object embedded somewhere which doesn't get a parent or -
>> beware - the wrong one (qApp?)
> 
> Perhaps I missing something, but if you wrote the code, you should know what 
> parent your objects do or don't have :)
> 
>> Qt can certainly not warn in all that cases.
>>
>> (1)
>>
>> Make moveToThread virtual. In this case moveToThread had to ensure all
>> related objects are living in the right thread. Which would work,
>> somehow, at least.
> 
> You can reimplement QObject::event() and watch for the QEvent::ThreadChange 
> event and do whatever you want (like move your static timers...).
> 

Does this "we use events instead of virtual methods" thingy Qt is 
currently driving to comes from the quest for binary compatibility 
between 4.x releases? The cost for this is high: extending the API in a 
  binary compatible manner can be done only without new virtual methods. 
This leads to adding new interfaces through the backdoor, like using new 
event types, new enums etc. Even if they were well-documented - which 
theay aren't in all cases - this lead to a state where a programmer just 
"needs to know" instead of simply looking at what is exposed in the C++ 
interfaces.

If you come from a solid C++ background you should get along easily with 
the interface description of a class. (i.e. signals, slots, methods, 
virtual methods and the like.) These days Qt tends to hide a lot of an 
object's interface in enums and co. While this is a coherent move (type 
safety was obviously not a top-10 priority when QObject::connect was 
designed and re-designed for qt4) it doesn't help the API users to come 
to quick result: you must *simply know* really much about Qt4's 
internals to do some stuff.

In this case a natural choice for a C++ classicist would be to make 
moveToThread() virtual to let derived objects do whatever they need to 
do. This is something that can clearly be seen in the classes interface.

Brad, as I know you are Qt's multithreading man I hope to get through to 
you with this, and would really like to have certain aspects of the Qt4 
interface changed in Qt5.

/eno

Side-Notes:

MoveToThread seems poorly named. Actually, the object gets moved to a 
different "event loop". And while a thread "can have its own event loop" 
as the docs state, you cannot do much with that event loop - in 
constrast to the main event loop in Q(Core)Application. This seems 
strange to me. Couldn't QThread expose its internal event loop via some 
method?

--
 [ signature omitted ] 

Message 12 in thread

> Side-Notes:
> 
> MoveToThread seems poorly named. Actually, the object gets moved to a 
> different "event loop". 

Ok: please drop the "poorly named" line. Is my recently ;-) aquired 
understanding correct that "moveToThread" would move an object to a 
whole bunch of event loops: namely these that run within a spcified thread?


/eno

--
 [ signature omitted ] 

Message 13 in thread

On Thursday 14 December 2006 18:52, Enrico Thierbach wrote:
[snip]
> >> 	A() { connect(&tm, SIGNAL(timeout()), ...); }
> >>
> >> will never work as expected (And I love creating my QTimer's as static
> >> class members ;-).
> >
> > As *static* members, or normal members?
>
> As a normal member (See the code :-). I know this is easily worked
> around by
[snip]
>       A() { tm = new QTimer(this); connect(&tm, SIGNAL(timeout()), ...); }
>
> but besides that it costs a bit (an additional allocation on the heap) I
> feel it strange that the latter works while the former cannot.

In one case, you specify the parent, while in the second you don't. Doesn't 
seem strange to me at all.

> Note: I am used to use the QObject child/parent-relationship for exactly
> two purposes:
>
> 1) Defining a hierarchy of objects
> 2) Defining ownership of objects
>
> While even this is not-the-best-design-ever (what if the owner of an
> object is not its hierarchical parent, but, say, a list of objects or -
> horror - a shared pointer object of some kind) this gets simply overly
> used by adding additional meaning to it, here how thread affinity is
> determined and how moveToThread() works.

I'm having trouble parsing this :) Could you reword it, perhaps?

[snip]
> Brad, as I know you are Qt's multithreading man I hope to get through to
> you with this, and would really like to have certain aspects of the Qt4
> interface changed in Qt5.

There's nothing I can do about that. Keeping the whole Qt 5 series ABI 
compatible will require alot of the same techniques you see in Qt 4 (which 
were there in Qt 2 & 3 as well).

> Side-Notes:
>
> MoveToThread seems poorly named. Actually, the object gets moved to a
> different "event loop". And while a thread "can have its own event loop"
> as the docs state, you cannot do much with that event loop - in
> constrast to the main event loop in Q(Core)Application. This seems strange
> to me. 

I disagree. The method seem very aptly named, and the documentation backs it 
up. QObject::moveToThread() changes what QObject::thread() returns; it 
changes the object's thread affinity. And thread affinity is defined as the 
thread responsible for delivering events to the object.

Giving the method a name that describes what it does to the internals 

> Couldn't QThread expose its internal event loop via some method?

-- 
 [ signature omitted ] 

Message 14 in thread

Bradley T Hughes wrote:
> On Thursday 14 December 2006 18:52, Enrico Thierbach wrote:
> [snip]
>>>> 	A() { connect(&tm, SIGNAL(timeout()), ...); }
>>>>
>>>> will never work as expected (And I love creating my QTimer's as static
>>>> class members ;-).
>>> As *static* members, or normal members?
>> As a normal member (See the code :-). I know this is easily worked
>> around by
> [snip]
>>       A() { tm = new QTimer(this); connect(&tm, SIGNAL(timeout()), ...); }
>>
>> but besides that it costs a bit (an additional allocation on the heap) I
>> feel it strange that the latter works while the former cannot.
> 

> In one case, you specify the parent, while in the second you don't. Doesn't 
> seem strange to me at all.

This is ok, as long as you have control over the source. (and finally 
you hinted me to QEvent::ThreadChange) If you don't have it you might
find yourself in a position where you have an object which works nicely 
on the main loop, but once you move it to a different thread it 
currently stops working.

> 
>> Note: I am used to use the QObject child/parent-relationship for exactly
>> two purposes:
>>
>> 1) Defining a hierarchy of objects
>> 2) Defining ownership of objects
>>
>> While even this is not-the-best-design-ever (what if the owner of an
>> object is not its hierarchical parent, but, say, a list of objects or -
>> horror - a shared pointer object of some kind) this gets simply overly
>> used by adding additional meaning to it, here how thread affinity is
>> determined and how moveToThread() works.
> 
> I'm having trouble parsing this :) Could you reword it, perhaps?

Here it goes ;-)

Hierarchy of objects: defines an abstraction where one object is related 
to zero or more objects in a way that you can name them parents or 
childs. Read: tree,nodes,leaves etc.pp.

Ownership of objects: an object o1 is owned by another object o2 <==> if 
o2 gets destroyed o1 gets destroyed as well.

While these two concepts do often come in pairs they are not identical. 
For example an object could be part of two different hierarchies: 
obviously in such a case ownership cannot be taken by one or the other 
hierarchy, but must handled externally.

Adding the "thread affinity issue" just adds a third notion to the 
already heavily loaded QObject::children infrastructure: this time the 
assumption that a child of an object has the same thread affinity, and 
even more: a non-child is affine to the thread it creates it.

Note: the assumption that a child lives in the same thread as its parent 
is certainly useful in most cases. However, additional steps might have 
to be taken to fix thread affinity in some cases, and an API which 
allows that (and is accessible via the docs) should be added to do that.

> 
> [snip]
>> Brad, as I know you are Qt's multithreading man I hope to get through to
>> you with this, and would really like to have certain aspects of the Qt4
>> interface changed in Qt5.
> 
> There's nothing I can do about that. Keeping the whole Qt 5 series ABI 
> compatible will require alot of the same techniques you see in Qt 4 (which 
> were there in Qt 2 & 3 as well).
> 
I hope with "Keeping the whole Qt 5..." you don't mean Qt5 to be 
ABI-compatible with Qt4? And hopefully something can be done towards Qt 
5. Another argument supporting my stance may be on the time of invocation:

the API user does know when the "moveToThread()" method gets called (in 
exact the moment it gets called :) If the object had to handle the event 
  it cannot know th exact time of invocation, but only guess.

Besides in one of your previous mails you said:

 >>> You can reimplement QObject::event() and watch for the
 >>> QEvent::ThreadChange event and do whatever you want
 >>> (like move your static timers...).

This is actually a very precious hint. Even more as the docs (at least 
for Qt/Mac 4.2.1) dont say a word on this ;-)

>> Side-Notes:
>>
>> MoveToThread seems poorly named. Actually, the object gets moved to a 
>> different "event loop". And while a thread "can have its own event loop"
>> as the docs state, you cannot do much with that event loop - in
>> constrast to the main event loop in Q(Core)Application. This seems strange
>> to me. 
> 
> I disagree. The method seem very aptly named, and the documentation backs it 
> up. QObject::moveToThread() changes what QObject::thread() returns; it 
> changes the object's thread affinity. And thread affinity is defined as the 
> thread responsible for delivering events to the object.

But is it really the thread who delivers the events? The way I see it an 
event is sent directly via QObject::event() and friends, which is 
obviously only save if QObject::thread() is the current thread, or must 
be posted via QCoreApplication::postEvent() which then must add the 
event to the target's thread's event loop.

Right?

However, meanwhile I realized that *multiple* event loops (or at least 
QEventLoop objects) can live in a thread. Hence a name suggesting the 
object be moved to some event loop wouldn't be correct either.


> 
> Giving the method a name that describes what it does to the internals 
> 
>> Couldn't QThread expose its internal event loop via some method?
> 

I missed the answer to that?

Have a nice weekend,
/eno

--
 [ signature omitted ] 

Message 15 in thread

On Friday 15 December 2006 21:15, Enrico Thierbach wrote:
> While these two concepts do often come in pairs they are not identical.
> For example an object could be part of two different hierarchies:
> obviously in such a case ownership cannot be taken by one or the other
> hierarchy, but must handled externally.

From a theoretical point of view, yes, having a single object in multiple 
hierarchies is possible, but not in Qt :)

> Adding the "thread affinity issue" just adds a third notion to the
> already heavily loaded QObject::children infrastructure: this time the
> assumption that a child of an object has the same thread affinity, and
> even more: a non-child is affine to the thread it creates it.
>
> Note: the assumption that a child lives in the same thread as its parent
> is certainly useful in most cases. However, additional steps might have
> to be taken to fix thread affinity in some cases, and an API which
> allows that (and is accessible via the docs) should be added to do that.

I don't see the problem. If you don't like the default affinity, change it. 
This is what QObject::moveToThread() is for...

> I hope with "Keeping the whole Qt 5..." you don't mean Qt5 to be
> ABI-compatible with Qt4? And hopefully something can be done towards Qt
> 5. Another argument supporting my stance may be on the time of invocation:

I'm not talking about keeping Qt 5 ABI compatible with Qt 4; I'm talking about 
Qt 5.x being compatible with 5.y.

> the API user does know when the "moveToThread()" method gets called (in
> exact the moment it gets called :) If the object had to handle the event
>   it cannot know th exact time of invocation, but only guess.

The event is sent at the end of moveToThread(), so you know that if you get a 
ThreadChange event, moveToThread() has just finished what it needs to do and 
is about to return.

> Besides in one of your previous mails you said:
>  >>> You can reimplement QObject::event() and watch for the
>  >>> QEvent::ThreadChange event and do whatever you want
>  >>> (like move your static timers...).
>
> This is actually a very precious hint. Even more as the docs (at least
> for Qt/Mac 4.2.1) dont say a word on this ;-)

Indeed, I'll update the docs.

> But is it really the thread who delivers the events? The way I see it an
> event is sent directly via QObject::event() and friends, which is
> obviously only save if QObject::thread() is the current thread, or must
> be posted via QCoreApplication::postEvent() which then must add the
> event to the target's thread's event loop.
>
> Right?

Yes, it is the thread that delivers events to QObject::event().

> However, meanwhile I realized that *multiple* event loops (or at least
> QEventLoop objects) can live in a thread. Hence a name suggesting the
> object be moved to some event loop wouldn't be correct either.

Right. That's why the method is called moveToThread().

> >> Couldn't QThread expose its internal event loop via some method?
>
> I missed the answer to that?

Our standard answer: private impementation (P-IMPL). We don't expose the 
internals of Qt :)

-- 
 [ signature omitted ] 

Pages: Prev | 1 | 2 | Next