线程化:PyQt在队列中出现未知请求时出现故障,并且出现了#34;

时间:2015-08-11 22:00:16

标签: multithreading python-2.7 pyqt4

我正在开发的应用程序的一部分需要向一小群人发送一些电子邮件。由于连接到SMTP服务器并发送电子邮件可能需要一段时间,因此我想在此操作期间提供进度条。我之前几乎没有使用过线程,所以使用QThread来做这件事对我来说有点困难。

现在发生的事情是我可以实现一个运行良好的测试结构,但是当我尝试从我的应用程序的后端创建一个对象来实际执行任何电子邮件操作时,它会完全崩溃(就好像它一样)已经segfaulted),将其转储到控制台:

[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:179: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted

我发现搜索这些错误的唯一相关线程说的是错误实现的信号(对于PySide,PySide and QProgressBar update in a different thread),但在我的情况下,信号完全正常,直到我尝试创建该对象(根本不是基于Qt类的。)

这是我的GUI代码的简化版本:

class SendingDialog(QtGui.QDialog):
    def __init__(self, parent, optsDict, cls, zid):
        QtGui.QDialog.__init__(self)
        self.form = Ui_Dialog()
        self.form.setupUi(self)
        # initialize some class variables...

        self.beginConnect()
        self.thread = WorkerThread()
        self.thread.insertOptions(self.opts, self.cls, self.zid)
        self.thread.finished.connect(self.endOfThread)
        self.thread.serverContacted.connect(self.startProgress)
        self.thread.aboutToEmail.connect(self.updateProgress)
        self.thread.start()

    def beginConnect(self):
        # start busy indicator

    def startProgress(self):
        # set up progress bar

    def updateProgress(self):
        # increment progress bar

    def endOfThread(self):
        self.thread.quit()
        self.reject()

class WorkerThread(QtCore.QThread):
    serverContacted = QtCore.pyqtSignal(name="serverContacted")
    aboutToEmail = QtCore.pyqtSignal(name="aboutToEmail")

    def insertOptions(self, opts, cls, zid):
        self.opts = opts
        self.cls = cls
        self.zid = zid

    def run(self):
        # upon running the following line, the application crashes.
        emailman = db.emailing.EmailManager(self.opts, self.cls, self.zid)

如果我将一些虚拟代码放入run()睡眠,发出适当的信号或打印测试值,一切正常;但是一旦我尝试实例化EmailManager,整个事情就会崩溃。

EmailManager是一个来自object的不起眼的类,它采用了我给它的参数(opts是一个字典,cls是另一种类型的同样不起眼的对象,而zid只是一个简单的数字)。构造函数如下所示:

def __init__(self, optsDict, cls, zid):
    self.opts = optsDict
    self.cls = cls
    self.historyItem = HistoryItem(zid)
    self.studentsList = studentsInClass(cls)
    self.connection = None

我根据参数构建了几个其他对象,但除此之外,没有任何复杂或不寻常的事情发生。 db.emailing模块中的代码根本不使用Qt或线程。

我甚至不知道如何开始调试,所以对于可能发生的事情或我可以尝试找出的任何建议都将非常感激。

修改:如果它有用,请点击gdb的回溯(我不太了解发现它的原因)有用):

Program received signal SIGABRT, Aborted.
[Switching to Thread 0x7fffeb146700 (LWP 31150)]
0x00007ffff762acc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007ffff762acc9 in __GI_raise (sig=sig@entry=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff762e0d8 in __GI_abort () at abort.c:89
#2  0x00007ffff7623b86 in __assert_fail_base (
    fmt=0x7ffff7774830 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", 
    assertion=assertion@entry=0x7ffff6a4420d "!xcb_xlib_unknown_req_in_deq", file=file@entry=0x7ffff6a441db "../../src/xcb_io.c", line=line@entry=179, 
    function=function@entry=0x7ffff6a446b0 "dequeue_pending_request")
    at assert.c:92
#3  0x00007ffff7623c32 in __GI___assert_fail (
    assertion=0x7ffff6a4420d "!xcb_xlib_unknown_req_in_deq", 
    file=0x7ffff6a441db "../../src/xcb_io.c", line=179, 
    function=0x7ffff6a446b0 "dequeue_pending_request") at assert.c:101
#4  0x00007ffff69d479c in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#5  0x00007ffff69d55c3 in _XReply ()
   from /usr/lib/x86_64-linux-gnu/libX11.so.6
#6  0x00007ffff69bc346 in XGetWindowProperty ()
   from /usr/lib/x86_64-linux-gnu/libX11.so.6
#7  0x00007ffff69bb22e in XGetWMHints ()
   from /usr/lib/x86_64-linux-gnu/libX11.so.6
#8  0x00007ffff4c87c4b in QWidgetPrivate::setWindowIcon_sys(bool) ()
   from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#9  0x00007ffff4c38405 in QWidget::create(unsigned long, bool, bool) ()
   from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#10 0x00007ffff4c4086a in QWidget::setVisible(bool) ()
   from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#11 0x00007ffff509956e in QDialog::setVisible(bool) ()
   from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#12 0x00007ffff5c24b7c in ?? ()
   from /usr/lib/python2.7/dist-packages/PyQt4/QtGui.so
#13 0x00007ffff5099026 in QDialog::exec() ()
   from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#14 0x00007ffff5be5fb5 in ?? ()
   from /usr/lib/python2.7/dist-packages/PyQt4/QtGui.so
#15 0x000000000049968d in PyEval_EvalFrameEx ()
#16 0x00000000004a090c in PyEval_EvalCodeEx ()
#17 0x0000000000499a52 in PyEval_EvalFrameEx ()
#18 0x00000000004a1c9a in ?? ()
#19 0x00000000004dfe94 in ?? ()
#20 0x00000000004dc9cb in PyEval_CallObjectWithKeywords ()
#21 0x000000000043734b in PyErr_PrintEx ()
#22 0x00007ffff186fd4d in ?? ()
   from /usr/lib/python2.7/dist-packages/sip.so
#23 0x00007ffff14b2ece in ?? ()
   from /usr/lib/python2.7/dist-packages/PyQt4/QtCore.so
#24 0x00007ffff45be32f in ?? ()
   from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#25 0x00007ffff79c1182 in start_thread (arg=0x7fffeb146700)
    at pthread_create.c:312
#26 0x00007ffff76ee47d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

1 个答案:

答案 0 :(得分:13)

哇,这太模糊了。

除非明确设置为X11窗口函数,否则它们显然不是线程安全的,并且无论出于何种原因,PyQt都不会自动将它们设置为。这可以通过在QApplication构造函数之前添加以下内容来更正:

QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)

请参阅QApplicationAttributes上的文档。

对于它的价值,EmailManager现在在线程中启动时正常工作,因为它使用共享的SQLite数据库连接来构造其他对象,这与{{{ 1}}库。我现在也遇到了分段错误。但这个特殊问题至少已经解决了。