[PyQt] Freezes and crashes with signal autoconnection
phil at riverbankcomputing.com
Tue Oct 13 11:41:09 BST 2009
On Sun, 11 Oct 2009 14:36:37 -0700 (PDT), Christian Roche
<christian.roche.fr at gmail.com> wrote:
> Phil Thompson-5 wrote:
>> Can you try with the latest installer (though it does contain a nasty
>> thread-related regression).
>> Do you have a test case?
> Hi Phil,
> I'm currently using PyQt 4.6-1 with Python 2.6.3. I think I've been able
> isolate a http://www.nabble.com/file/p25847873/main.py test case that
> crashes consistently and demonstrates at least one of the problems I've
> experiencing with PyQt multithreading.
> In this piece of code, when the time delay in the GalleryCreator thread
> greater than the delay in the GalleryModel appendLink slot, the
> works fine. However if this delay is set to a value less than the latter,
> then it crashes after a few iterations. It seems that the
> object doesn't like it when a queue of pending events is forming, with
> custom data types.
> Also in the second case, the application won't crash if you use
> Qt.BlockingQueuedConnection instead of AutoConnection (see line 111).
> makes sense since in that case no event queue is forming, the Model
> has enough time to consume the incoming event before a new one is posted.
> The application won't crash either if you use 'PyQt_PyObject' instead of
> ImageLink in the signal argument (see line 88). Don't ask me why :-)
> Note: I see a similar behaviour on Linux.
I think this is all one problem and is nothing to do with threads. There is
a (necessary) change of behaviour (documented in the current snapshot) when
wrapping a Python sub-class of a QObject in a QVariant.
Previously this was first wrapped in a PyQt_PyObject which managed the
reference counts for you so that you didn't need to maintain an explicit
reference to the QObject sub-class (the ImageLink instance in your case).
The problem with that is that nothing outside of PyQt knows what a
PyQt_PyObject is. So C++ code that has a slot or a dynamic property
expecting a QObject*.
The current behaviour means that you can pass your ImageLink instance
around to code that doesn't know anything about Python - but it means it
won't manage the reference count for you. In your example your ImageLink
instance is being garbage collected too soon. Using a blocking connection
serialises access to it making sure that it is used before being garbage
collected. Using PyQt_PyObject as the signal signature has the effect of
enforcing the previous behaviour. Hence no crash in either case.
More information about the PyQt