[PyQt] Freezes and crashes with signal autoconnection

Phil Thompson phil at riverbankcomputing.com
Wed Oct 14 09:00:48 BST 2009


On Tue, 13 Oct 2009 18:47:47 -0700 (PDT), Christian Roche
<christian.roche.fr at gmail.com> wrote:
> Phil Thompson-5 wrote:
>> 
>> 
>> 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.
>> 
>> Phil
>> 
> 
> Hi Phil,
> 
> thanks a lot for the explanation, it all makes sense. However I've not
been
> able to fully test it because I bumped into another issue: so now thanks
to
> using Qt.BlockingQueuedConnection, my QThread instances send a signal and
> wait when they have finished, so the destination slot has time to process
> the ImageLink parameter. But I cannot keep track of the active threads in
> this slot anymore. Previously I would do
> 
>   thread = QThread(link)
>   threadList[link] = thread
> 
> when creating a new QThread and
> 
>   threadList[link].wait()
>   del threadList[link]
> 
> in the termination slot, in order to keep the necessary references to the
> existing threads. But now since my threads are blocked, I cannot "forget"
> them in this slot.
> 
> So I tried to create a new slot onto which I would connect the finished()
> signal; at that time I'm sure that the thread is gone, but how can I
> identify which one? There's no parameter to the signal, and trying to get
a
> reference to the emiting thread by using self.sender() doesn't work
either,
> I guess because precisely the thread is gone for good at that point. So
how
> am I supposed to keep track of those running threads in this situation ?
Or
> am i totally off ?

If you have a list of the QThread instances you can scan the list when
finished() is received to see which one it is. There is an obvious race
condition with that approach.

You could define a method in your QThread sub-class that finished() is
connect to. That method just emits another signal but with the QThread
instance as an argument.

Phil


More information about the PyQt mailing list