[PyQt] Multithreading, signals, reference counting and crash

Phil Thompson phil at riverbankcomputing.com
Thu Feb 11 13:32:24 GMT 2016


On 11 Feb 2016, at 1:14 pm, Ilya Volkov <nxsofsys at gmail.com> wrote:
> 
> Hi all,
> 
> We have some problems with sending python objects between threads by signals with Qt.QueuedConnection type. If python object was sent from one thread to another by signal, its reference counter does not increment, and object can be destroyed in first thread before slot in second thread will be called which leads to a crash.
> 
> I made example which illustrates this situation (also available on github: https://gist.github.com/nxsofsys/d80487e7605eb7061d88 ):
> 
> from PyQt5.QtCore import QObject, QThread, pyqtSignal
> from PyQt5.QtCore import qDebug, QCoreApplication, Qt
> import time
> import sys
> 
> class SomeThread(QObject):
> 
>     signal = pyqtSignal(QObject)
> 
>     def __init__(self):
>         QObject.__init__(self)
>         self.thread = QThread()
>         self.wait = self.thread.wait
>         #
>         # self.signal.connect(self.signalHandler, type = Qt.QueuedConnection)
>         self.moveToThread(self.thread)
>         self.signal.connect(self.signalHandler, type = Qt.QueuedConnection)
>         self.thread.started.connect(self.run)
>         self.thread.start()
> 
>     def signalHandler(self, obj):
>         qDebug("signalHandler obj ref counts: " + str(sys.getrefcount(obj)))
> 
>     def run(self):
>         qDebug("Thread sleeps for 1 sec")
>         time.sleep(1)
>         qDebug("Process events now")
>         QCoreApplication.processEvents()
>         self.thread.exit()
> 
> app = QCoreApplication([])
> th = SomeThread()
> 
> # obj = QObject()
> def someFunc():
>     obj = QObject()
>     qDebug("obj ref counts before emit: " + str(sys.getrefcount(obj)))
>     th.signal.emit(obj)
>     qDebug("obj ref counts after emit: " + str(sys.getrefcount(obj)))
> 
> someFunc()
> qDebug("Process main events")
> QCoreApplication.processEvents()
> qDebug("Process main events done")
> th.thread.wait()
> 
> I think in this case signal emit should increment reference counter for a python object preventing it from destruction. Just comment "obj = QObject" in someFunc and uncomment  "# obj = QObject()" before function definition, and script runs without crash.

When would you then decrement the reference count again?

It's up to you to make sure that objects you emit stay alive - a C++ version of your example would crash as well.

Phil


More information about the PyQt mailing list