2014-02-11 48 views
5
QApplication.quit

時注意:我還張貼這在PyQt的郵件列表 - 在這裏我要回答我的問題,如果一個很好的答案出現在那裏。PyQt的:偶爾使用的段錯誤

執行 QApplication.quit(),可能與libQt5Network.so和/或 QtWebKit的時候我有偶爾段錯誤的問題。

首先,我使用了3個測試系統:

  • Arch Linux的,PyQt的5.2,Qt的5.2.0,3.3.3的Python
  • 的Ubuntu 13.10,PyQt的5.0.1,QT 5.0.2,3.3.2的Python在VM
  • Windows 7中,PyQt的5.2,Qt的5.2.0,3.3.3的Python

這些事故沒有發生拱對我來說,到目前爲止,經常在 Ubuntu,並不時在Windows中。 (雖然視窗只是一種猜測 ,我剛剛得到這個python.exe是不工作了 FOO)

初始崩潰

我第一次在一個大的(GER)項目,qutebrowser注意到了這個問題, 它(在Ubuntu)輸入:quit時,給了我這個堆棧跟蹤:

#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的)。

最小示例

然後我與之後的第二與QTimer自動退出本身 最小示例再次嘗試。我不得不在一個循環 運行約一分鐘左右的時間就發生了:

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_() 

這給了我一個非常類似於堆棧跟蹤(在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的)。

任何人有一個想法,什麼錯呢?一些魔術與東西 垃圾收集錯誤的方式?我也在PyQt4上嘗試了一些 解決方法*來解決類似的問題,但是 也沒有幫助。

*找不到它被描述的StackOverflow回答 - 基本上 之前運行exec_()設置QtWidgets.qAppQApplication實例,並None之後。

回答

7

我一直在努力追趕段錯誤的PyQt的/PySide相當長的一段時間。基本上我發現,大多數segfaults可以歸咎於圖書館的異步性質(因此也適用於我們)。

就您的確切示例而言,您已將timeout信號連接到quit方法。這裏可能發生的情況是,如果超時,quit被調用,並且進程終止時,突然對應用程序對象的所有引用都是無效的。但是當這個操作發生時,QT的事件循環仍在運行,它試圖訪問它的QNetworkAccessManager來發送另一個信號,但是對該內存位置的引用已經無效,因此發生了段錯誤。

在這些情況下需要完成的一項工作是執行一種關閉方法,它將確保所有操作都已停止,並以正確的順序刪除正在使用的組件,然後,就在這時,請允許退出。

我寫了詳細的主題在這裏,包括QtWebKit應用安全關機方法:https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08

+0

謝謝!您的教程似乎對其他將來的問題也很有用。如果你有時間,你能否看看我的[執行它](http://git.the-compiler.org/qutebrowser/commit/?id=0abb5cf7384c1ccfb2b829cbf26fcc92add08bc6)(原始崩潰,而不是最小的例子) )看起來合理? –

+1

不客氣:)我看了一下你的代碼,但是我沒有真正測試過。正如我在教程中提到的那樣,我注意到的是,這個'deleteLater'方法也是異步的,所以可能發生的情況是您的'shutdown'方法完成,'deleteLater'被安排,並且應用程序退出,但這些對象並沒有真正被刪除得這麼快。我通過將'destroy'信號連接到一個方法來解決這個問題,我檢查是否所有組件都被成功刪除,然後才允許應用程序退出 – andrean

+0

你說得對,我沒有想到這一點。我做了[實現](http://git.the-compiler.org/qutebrowser/commit/?id=8c37e1c33a11fdcb26ac985b72fae27e083b158a),至少在我的(少數)測試中,目前爲止沒有段錯誤。 –