我已经实现了 Qt Threading docs 中描述的工作模式版本。 .
我使用信号/槽
在工作线程和主线程之间发送数据。
在定义Signal
时,我已将参数签名类型设置为object
,因为我相信它应该允许我通过Signal传递任何Python对象
.
result_ready = QtCore.Signal(object)
但是,当我尝试通过 Signal
传递 None
时,它会使 python 崩溃。仅当尝试跨线程传递Signal
时才会发生这种情况。如果我注释掉 self.worker.moveToThread(self.thread) 行,它就会起作用,并且 None
成功通过 Signal
。
为什么我在这种情况下无法传递 None
?
我正在使用 PySide 1.2.2
和 Qt 4.8.5
。
import sys
from PySide import QtCore, QtGui
class Worker(QtCore.QObject):
result_ready = QtCore.Signal(object)
@QtCore.Slot()
def work(self):
print 'In Worker'
# This works
self.result_ready.emit('Value')
# This causes python to crash
self.result_ready.emit(None)
class Main(QtGui.QWidget):
def __init__(self):
super(Main, self).__init__()
self.ui_lay = QtGui.QVBoxLayout()
self.setLayout(self.ui_lay)
self.ui_btn = QtGui.QPushButton('Test', self)
self.ui_lay.addWidget(self.ui_btn)
self.ui_lay.addStretch()
self.setGeometry(400, 400, 400, 400)
self.worker = Worker()
self.thread = QtCore.QThread(self)
self.worker.moveToThread(self.thread)
self.thread.start()
self.ui_btn.clicked.connect(self.worker.work)
self.worker.result_ready.connect(self.handle_worker_result)
@QtCore.Slot(object)
def handle_worker_result(self, result=None):
print 'Handling output', result
def closeEvent(self, event):
self.thread.quit()
self.thread.wait()
super(Main, self).closeEvent(event)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
obj = Main()
obj.show()
app.exec_()
最佳答案
这看起来像一个 PySide 错误。相同的示例代码在 PyQt4 中的工作方式与预期完全一样。
问题出在 type of signal connection 。对于跨线程信号,除非您另外指定,否则将使用 QueuedConnection。如果示例代码中的连接类型更改为 DirectConnection
,它将按预期工作 - 但当然它不再是线程安全的。
QueuedConnection
会将事件发布到接收线程的事件队列。但为了使其线程安全,Qt 必须序列化发出的参数。然而,PySide 显然需要在这里注入(inject)一些魔法来处理 Qt 不了解的 python 类型。如果我不得不猜测,我敢打赌 PySide 错误地将 python None
对象转换为 C++ NULL 指针,这显然会在以后产生严重的后果。
如果您想解决这个问题,我想您可以发出自己的哨兵对象作为 None
的占位符。
更新:
发现错误,PYSIDE-17 ,发布于 2012 年 3 月!遗憾的是,建议的补丁似乎从未经过审查。
关于python - 如何跨线程发送无信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35712870/