【发布时间】:2018-02-12 17:13:12
【问题描述】:
我正在使用 PyQt5 和 QML (Qt 5.7.1) 构建一个应用程序,该应用程序控制多个硬件并且遇到了一个问题,即一个接一个地发出 10 多个信号会导致应用程序出现段错误。我附上了一个 MWE 来演示这个问题。
MWE 创建一个后台线程,然后每毫秒使用信号更新主线程中的两个标签。该示例在 Windows 7 和 linux 中随机出现段错误,但通常在一秒钟内。我在 linux 中安装了 Qt 调试符号,发现它在 QV4 中的随机位置出现了段错误,尽管每个段错误的调用似乎都与内存管理器有关。
此时我已经陷入了死胡同,阻止段错误的唯一方法是在每个信号发射之间放置 QThread.msleep() 调用,随着应用程序的增长,这已经变得站不住脚了。
这是我第一次使用 Qt/QML,所以如果这不是使用信号的正确方法,我深表歉意,但我找不到任何说不要以这种方式使用它们的东西。
StartPage.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
id: mainWindow
ColumnLayout {
Label {
id: runLabel
property int timesRun: 0
text: "Number of times run: " + timesRun
Connections {
target: worker
onDoSomethingDone: {
runLabel.timesRun = runLabel.timesRun + 1;
}
}
}
Label {
id: dataLabel
property real value: 0.0
text: "Data: " + value
Connections {
target: worker
onDataChanged: {
dataLabel.value = data
}
}
}
}
}
thread_test.py
>#!/usr/bin/env python3
import sys
import os
import signal
from PyQt5.QtCore import QObject, QThread, pyqtSlot, pyqtSignal
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtWidgets import QApplication
class Worker(QObject):
doSomethingDone = pyqtSignal()
dataChanged = pyqtSignal(float, arguments=['data'])
runWorkSignal = pyqtSignal()
_count = 0.0
def __init__(self):
super().__init__()
self.runWorkSignal.connect(self.do_something)
@pyqtSlot()
def do_something(self):
while (True):
self._count += 0.5
self.doSomethingDone.emit()
self.dataChanged.emit(self._count)
QThread.msleep(1)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal.SIG_DFL)
# Switch to the script directory so relative paths work correctly.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
workObject = Worker()
workThread = QThread()
engine.rootContext().setContextProperty('worker', workObject)
engine.load('qml/StartPage.qml')
workThread.started.connect(workObject.do_something)
workObject.moveToThread(workThread)
workThread.start()
sys.exit(app.exec_())
【问题讨论】:
-
尝试在创建后立即将工作对象移动到线程,并且在它被其他任何东西引用之前。有时,如果他们正在使用尚未移动到要运行的线程的对象,事情会变得混乱。
-
@three_pineapples 实际上我最初是这样做的,但这在 QML 中引发了错误。将其导出到 QML 后将其移至线程使 QML “快乐”,但显然也被破坏了。
标签: python multithreading qt pyqt qml