2014-02-11 7 views
5

Hinweis: Ich habe dies auch auf der PyQt-Mailingliste gepostet - ich beantworte meine eigene Frage hier, wenn eine gute Antwort dort kommt.PyQt: gelegentliche segfaults bei Verwendung von QApplication.quit

Ich habe Probleme mit gelegentlichen segfaults haben, wenn QApplication.quit() ausgeführt wird, möglicherweise im Zusammenhang mit libQt5Network.so und/oder QtWebKit.

Vor allem die drei Testsysteme Ich verwende:

  • Arch Linux, PyQt 5.2, Qt 5.2.0, Python 3.3.3
  • Ubuntu 13.10, PyQt 5.0.1, Qt 5.0.2, Python 3.3.2 in einem VM
  • Windows 7, PyQt 5.2, Qt 5.2.0, Python 3.3.3

Diese Abstürze nie so weit für mich auf Arch passiert ist, sehr oft auf Ubuntu und von Zeit zu Zeit in Windows. (Obwohl Windows ist nur eine Vermutung , bekomme ich nur diese python.exe nicht funktioniert mehr foo.)

Original-Absturz

ich zum ersten Mal das Problem in einem großen (ger) Projekt bemerkt, qutebrowser, wo es mir diese stacktrace gab, als :quit (auf Ubuntu) eingeben:

#0 0xb5c296fc in QMutex::lock()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#1 0xb3bdd97d in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#2 0xb3bdf0d0 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#3 0xb3bd4418 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#4 0xb3bd8b1e in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#5 0xb5dedf10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#6 0xb5dee48b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#7 0xb5e59155 in QIODevice::readyRead()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#8 0xb3bb1f14 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#9 0xb3ba4d99 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#10 0xb3bc03bb in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#11 0xb6483a54 in QApplicationPrivate::notify_helper(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#12 0xb6488e66 in QApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#13 0xb6bb7e80 in sipQApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-33m-i386-linux-gnu.so 
#14 0xb5dc737a in QCoreApplication::notifyInternal(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#15 0xb5e11f67 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#16 0xb5aaf83e in g_main_context_dispatch() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#17 0xb5aafbe8 in ??() from /lib/i386-linux-gnu/libglib-2.0.so.0 
#18 0xb5aafca8 in g_main_context_iteration() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#19 0xb5e1138f in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#20 0xb5dc5c06 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#21 0xb5dc6014 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#22 0xb5c2b90b in QThread::exec()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#23 0xb5c2b99b in QThread::run()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#24 0xb5c2fa08 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#25 0xb7774d78 in start_thread (arg=0xa5314b40) at pthread_create.c:311 
#26 0xb76ac01e in clone() at ../sysdeps/unix/sysv/linux/i386/clone.S:131 

Core dump here (15MB, gzip).

Minimal Beispiel

Dann habe ich versucht wieder mit einem minimalen Beispiel, das sich automatisch nach einer Sekunde mit einer QTimer beendet. Ich hatte es in einer Schleife für etwa eine Minute oder so laufen, bevor es passiert ist:

from PyQt5.QtCore import QUrl, QTimer 
from PyQt5.QtWidgets import QApplication 
from PyQt5.QtWebKitWidgets import QWebView 

app = QApplication([]) 
wv = QWebView() 
wv.load(QUrl("http://www.heise.de/")) 
t = QTimer() 
t.timeout.connect(QApplication.quit) 
t.start(1000) 
wv.show() 
app.exec_() 

Dies gab mir diese sehr ähnlich stacktrace (auf Ubuntu):

#0 0xb6cfd8d2 in QCoreApplication::postEvent(QObject*, QEvent*, int)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#1 0xb6d21c83 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#2 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#3 0xb3e47935 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#4 0xb3dcf687 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#5 0xb3e483b3 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#6 0xb6d21f10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#7 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#8 0xb3e43fe5 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#9 0xb3d93b1e in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#10 0xb3d94630 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#11 0xb3d9471b in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#12 0xb6d21f10 in QMetaObject::activate(QObject*, int, int, void**)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#13 0xb6d2248b in QMetaObject::activate(QObject*, QMetaObject const*, int, void**)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#14 0xb6d8d155 in QIODevice::readyRead()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#15 0xb3e09f14 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#16 0xb3dfcd99 in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#17 0xb3e183bb in ??() from /usr/lib/i386-linux-gnu/libQt5Network.so.5 
#18 0xb492ba54 in QApplicationPrivate::notify_helper(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#19 0xb4930e66 in QApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Widgets.so.5 
#20 0xb505fe80 in sipQApplication::notify(QObject*, QEvent*)() 
    from /usr/lib/python3/dist-packages/PyQt5/QtWidgets.cpython-33m-i386-linux-gnu.so 
#21 0xb6cfb37a in QCoreApplication::notifyInternal(QObject*, QEvent*)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#22 0xb6d45f67 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#23 0xb65f483e in g_main_context_dispatch() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#24 0xb65f4be8 in ??() from /lib/i386-linux-gnu/libglib-2.0.so.0 
#25 0xb65f4ca8 in g_main_context_iteration() 
    from /lib/i386-linux-gnu/libglib-2.0.so.0 
#26 0xb6d4536d in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#27 0xb6cf9c06 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#28 0xb6cfa014 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#29 0xb6b5f90b in QThread::exec()() 
    from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#30 0xb6b5f99b in QThread::run()() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#31 0xb6b63a08 in ??() from /usr/lib/i386-linux-gnu/libQt5Core.so.5 
#32 0xb7798d78 in start_thread (arg=0xa7812b40) at pthread_create.c:311 
#33 0xb76d001e in clone() at ../sysdeps/unix/sysv/linux/i386/clone.S:131 

Coredump here (15MB, gzip).

Hat jemand eine Idee, was schief läuft? Irgendeine Magie mit Sachen Müll-gesammelt in die falsche Richtung? Ich versuchte auch einige Workarounds * für ähnliche Symptome auf PyQt4, aber das tat Hilfe entweder nicht.

* kann nicht die Stackoverflow-Antwort finden, wo es beschrieben wurde - grundsätzlich QtWidgets.qApp auf die QApplication Instanz vor Einstellung exec_() ausgeführt wird, und auf None danach.

Antwort

7

Ich habe auf den Fang segfaults in PyQt/pyside seit geraumer Zeit arbeiten. Grundsätzlich fand ich, dass die meisten der segfaults auf die asynchrone Natur der Bibliothek (also auch auf uns) zurückgeführt werden können.

Für Ihr genaues Beispiel haben Sie das Signal timeout an die quit-Methode angeschlossen. Was hier passieren könnte ist, dass im Falle eines Timeout, quit aufgerufen wird, und wenn der Prozess beendet wird, plötzlich alle Verweise auf die Objekte der Anwendung ungültig sind. Aber während dieser Vorgang war QT 's Ereignisschleife noch ausgeführt, und es versuchte, es ist QNetworkAccessManager, um ein anderes Signal zu senden, aber der Verweis auf diesen Speicherort war bereits ungültig, so dass die segfault passiert ist.

In diesen Fällen müssen Sie eine Art Shutdown-Methode implementieren, die dafür sorgt, dass alle Operationen gestoppt werden. Löschen Sie die QT Komponenten, die Sie verwenden, in der richtigen Reihenfolge Rufen Sie dann einfach das Beenden an.

Ich schrieb über das Thema hier näher, für QtWebKit Anwendungen eine sichere Abschaltung Verfahren umfasst: https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08

+0

Dank! Ihr Tutorial scheint auch für andere zukünftige Probleme nützlich zu sein. Wenn du Zeit hast, könntest du einen Blick darauf werfen, ob meine [Umsetzung davon] (http://git.the-compiler.org/qutebrowser/commit/?id=0abb5cf7384c1ccfb2b829cbf26fcc92add08bc6) (für den ursprünglichen Absturz, nicht das minimale Beispiel)) sieht vernünftig aus? –

+1

Gern geschehen :) Ich habe einen Blick in Ihren Code geworfen, aber ich habe es tatsächlich nicht getestet. Wie ich bereits im Tutorial erwähnt habe, ist diese "deleteLater" -Methode ebenfalls async, was passieren könnte, ist, dass Ihre 'shutdown' Methode beendet ist,' deleteLater' geplant ist, und die App beendet wird. aber die Objekte werden nicht so schnell gelöscht. Ich löste es, indem ich das 'zerstörte' Signal mit einer Methode verband, wo ich überprüfe, ob alle Komponenten erfolgreich gelöscht wurden, und erlaube der App dann nur zu beenden. – andrean

+0

Du hast Recht, ich habe nicht daran gedacht. Das habe ich jetzt auch umgesetzt (http://git.the-compiler.org/qutebrowser/commit/?id=8c37e1c33a11fdcb26ac985b72fae27e083b158a), und zumindest in meinen (wenigen) Tests bisher keine segfaults. –

Verwandte Themen