Deadlock On Exit With PySide And QFileSystemWatcher
Last year Nokia started developing their own Python bindings for Qt, PySide, when they couldn’t persuade Riverbank Computing to relicense PyQt under a more liberal license. While developing DjangoDE I made the choice of which library to use configurable. When running under PyQt everything worked fine, but when using PySide the program hung on exit.
Using gdb to see where it was hanging points to QFileSystemWatcher, which has the following comment in the destructor.
Note: To avoid deadlocks on shutdown, all instances of QFileSystemWatcher need to be destroyed before QCoreApplication. Note that passing QCoreApplication::instance() as the parent object when creating QFileSystemWatcher is not sufficient.
The following code will demonstrate the issue.
import sys
#from PyQt4 import QtGui
from PySide import QtGui
app = QtGui.QApplication(sys.argv)
file_browser = QtGui.QTreeView()
file_model = QtGui.QFileSystemModel()
file_model.setRootPath("/")
file_browser.setModel(file_model)
file_browser.show()
sys.exit(app.exec_())
As the comment says, we need to ensure that the QFileSystemWatcher
object, which is created by
QFileSystemModel
, is destroyed before QApplication
. To do this we can connect to the
lastWindowClosed
and ensure that the QFileSystemModel
is fully destroyed.
import gcn
def app_quit():
global file_browser
file_browser = None
gc.collect()
app.lastWindowClosed.connect(app_quit)
It’s not clear why this code would work on PyQt and not PySide, but it is clearly related to the order the
objects are deleted. Given the comment in the Qt documentation though you should probably not rely on it
working on PyQt and ensure yourself that the QApplication
is the last Qt object to be destroyed.
Comments