[PyQt] Multithreading, signals, reference counting and crash
bjones at ece.msstate.edu
Mon Feb 15 04:47:12 GMT 2016
Thanks for the response and the explanation. That was very helpful!
On Sat, Feb 13, 2016 at 3:00 AM, Phil Thompson <phil at riverbankcomputing.com>
> On 12 Feb 2016, at 10:39 pm, Jones, Bryan <bjones at ece.msstate.edu> wrote:
> > Phil,
> > Thanks for your response. I'm specifically concerned about the context
> of passing data between threads using the signal/slot mechanism. As you
> say, in the direct or blocking case, there's no concern with object
> > To test this, I modified Ilya's code to make it easier to test the
> signal/slot mechanism on different types. A QObject fails, but standard
> Python types (dict, list, object, etc.) pass, showing that their reference
> count increases after an emit. I can even pass a list containing a QObject
> safely. This suggests to me that your code increases the reference count
> when emitting pure Python objects, but not when emitting Qt objects. Based
> on some digging (see below), I would expect Qt objects to arrive safely to
> the slot because they're copied, but this doesn't work in practice. What's
> safe and what's not safe when using the signal/slot mechanism when crossing
> thread boundaries?
> PyQt tries to convert a Python object to something that the Qt meta-type
> system understands. If it can't then it wraps it in a PyQt_PyObject. This
> is registered with the meta-type system and part of its job is to manage
> the reference count of the object as it gets copied around the meta-type
> If PyQt can convert the object then it's up to the meta-type system to
> manage the lifecycle of the converted C++ instance as you describe below.
> It would be wrong for PyQt to use PyQt_PyObject for every type of Python
> object because that would mean you couldn't connect to slots implemented in
> C++ that do not understand PyQt_PyObject. However you can explicitly use
> PyQt_PyObject yourself by declaring the signal as...
> mysig = pyqtSignal('PyQt_PyObject')
> ...and this will "protect" the object even if it was a QObject. I was
> about to include the link to the relevant bit of the documentation and
> realised that it's only in the current snapshot and I must have added it
> (the documentation) since the last release.
> > Looking at the Qt source, from what I understand:
> > 1. In qobject.cpp, the queued_activate function is used to post an
> signal to another thread's event queue. (See qobject.cpp::activate for the
> generic mechanism used to emit a signal, which calls queued_activate for
> queued connections). Here's a helpful blog post on the topic.
> > 2. To do this, queued_activate makes a copy of each argument by invoking
> QMetaType::create (which invokes that type's copy constructor) in the
> signal being emitted.
> > 3. When all signals have been delivered, QMetaCallEvent::destroy frees
> memory used by this copy.
> > Based on this, I conclude that Qt allows the emission of signals with
> any type registered with the Qt meta-type system by copying the type,
> delivering it to all slots, then destroying the copy.
> Your analysis is correct, but with one key omission. You cannot copy
> QObject instances. It is QObject* that is supported by the meta-type system
> and not QObject. You still have to manage the lifecycle of what the pointer
> points to (or use PyQt_PyObject).
Bryan A. Jones, Ph.D.
Department of Electrical and Computer Engineering
231 Simrall / PO Box 9571
Mississippi State University
Mississippi state, MS 39762
bjones AT ece DOT msstate DOT edu
Our Master, Jesus Christ, is on his way. He'll show up right on
time, his arrival guaranteed by the Blessed and Undisputed Ruler,
High King, High God.
- 1 Tim. 6:14b-15 (The Message)
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the PyQt