[Development] QThread usage/guidance

Olivier Goffart olivier at woboq.com
Wed Oct 10 19:20:18 CEST 2012


On Wednesday 10 October 2012 17:45:51 Giuseppe D'Angelo wrote:
> On 10 October 2012 16:00, Tony Van Eerd <tvaneerd at rim.com> wrote:
> > I don't have any use cases, but I can't imagine the example recommendation
> > of
> > 
> > connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
> > 
> > working as expected unless deleteLater() happens on the same thread as
> > finished(), via a direct call.
> 
> Why do you say so?
> 
> Without looking at the implementation, the theory should tell us:
> 
> 1) finished() emitted from the "new thread", QThread living in the
> "parent thread": a queued call is used automatically.

If you connect to an object living in the finishing thread, it will be a 
direct conection.
Also, you could explicitly state Qt::DirectConnection while connecting.

> Since you can't
> be certain about when the event loop in the parent thread picks the
> deletion event up (*) and tries to delete the QThread object (which
> can happily crash your program, if the managed thread is still
> running)

You can safely delete a QThread once the finished signal has been emitted
(tested in tst_QThread::destroyFinishRace )

> , lock a mutex before emitting finished() and unlock it when
> you're really done with the thread. Then lock the same mutex in the
> QThread dtor, so it can't be run while you're cleaning up.

We solve it in a similar way,
but you can't keep the mutex locked while emiting finished, since signal 
directly connected to it would possibly lock other mutex and then run into a 
dead lock.
Generaly, you can't keep a mutex locked when you call "user" code (emitting 
signals or calling virtual method).


> 2) finished() emitted from the "new thread", QThread living in its
> thread (moveToThread(this), etc.): direct connection used
> automatically, which will cause deleteLater to immediately post a
> deferred delete event. It will be picked up some time later (i.e. it
> won't deadlock with the aforementioned mutex), when the last round of
> deferred events is dispatched. By carefully coding it, you can achieve
> "delete this" in C++.

moveToThread(this) is really a bad idea.
deleting the QThread object in a slot dirrectly connected to finished is an 
undefined behaviour,  likely a crash.

We don't want to support this.
 
> 3) finished() emitted from the "parent thread", QThread living in the
> "parent thread": this requires us to reason about how do you emit such
> signal from the parent thread. If you resort to post an event to the
> QThread instance, event which will be dispatched from the parent
> thread's event loop and will cause the emission of the signal, you
> pretty much reinvented 1)... (Before you think about doing something
> strange, you can't emit Qt signals from, say, UNIX signal handlers.)
> 
> 4) finished() emitted from the "parent thread", QThread living in its
> thread: this can't work in all cases, as the deletion event may be
> posted (to the thread's own event loop) after the thread itself has
> fully finished. In other words, this will leak the QThread instance;
> it's the equivalent of posting an event to an object living in a
> thread without an event loop running.

-- 
Olivier

Woboq - Qt services and support - http://woboq.com





More information about the Development mailing list