[英]Rapidly emitting signals in Qt causes a segfault
我正在使用PyQt5和QML(Qt 5.7.1)构建一个控制许多硬件的应用程序,并且遇到了一个问题,即一个接一个地发出10+信号会导致应用程序出现段错误。 我附加了MWE来演示该问题。
MWE创建一个后台线程,然后使用信号每毫秒更新主线程中的两个标签。 示例segfaults在Windows 7和linux中都是随机发生的,但通常不到一秒钟。 我在Linux上安装了Qt调试符号,并发现它在QV4中的随机位置进行了段错误修复,尽管每个段错误调用似乎都与内存管理器有关。
在这一点上,我已经QThread.msleep()
,唯一阻止segfaulting的事情是在每个信号发射之间放置QThread.msleep()
调用,随着应用程序的增长,它变得站不住脚了。
这是我第一次使用Qt / 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
}
}
}
}
}
#!/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_())
QML无法直接访问另一个线程,因此,如果将项目连接到另一个线程中的对象,则它会引起类似您所观察到的问题。 如果要访问另一个线程,则必须从Python端进行操作,即:
Worker(another thread) --> Proxy(main Thread) --> QML
您的解决方案是:
class Worker(QObject):
[...]
class Proxy(QObject):
doSomethingDone = pyqtSignal()
dataChanged = pyqtSignal(float, arguments=['data'])
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()
proxy = Proxy()
workObject.doSomethingDone.connect(proxy.doSomethingDone)
workObject.dataChanged.connect(proxy.dataChanged)
engine.rootContext().setContextProperty('worker', proxy)
engine.load('qml/StartPage.qml')
workThread.started.connect(workObject.do_something)
workObject.moveToThread(workThread)
workThread.start()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.