重用 QRunnable
Posted
技术标签:
【中文标题】重用 QRunnable【英文标题】:Re-using QRunnable 【发布时间】:2016-02-22 18:05:27 【问题描述】:我一直在尝试使用QRunnable
,以便启动和运行一些服务调用。我偶然发现了来自Qt documentation 的以下信息:
QThreadPool 支持多次执行同一个 QRunnable 从 QRunnable::run() 中调用 tryStart(this)。如果自动删除是 启用 QRunnable 将在最后一个线程退出时被删除 运行功能。使用相同的 QRunnable 多次调用 start() 当 autoDelete 启用时,会创建一个竞争条件,而不是 推荐。
有人能解释一下这是什么意思吗?我编写了以下代码,它允许我按顺序多次执行QRunnable
对象:
#!/usr/bin/env python
from PyQt4.QtCore import QRunnable, pyqtSlot, pyqtSignal, QObject, QThread, QThreadPool
from PyQt4.QtGui import QApplication, QWidget, QPushButton, QHBoxLayout, QLabel
from sys import exit, argv
from random import getrandbits
class ServiceCallSignals(QObject):
srv_status = pyqtSignal(bool)
srv_running = pyqtSignal(bool)
class ServiceCall(QRunnable):
def __init__(self):
super(ServiceCall, self).__init__()
self.signals = ServiceCallSignals()
def run(self):
self.signals.srv_running.emit(True)
call = bool(getrandbits(1))
print('QRunnable Thread ID: %d' % int(QThread.currentThreadId()))
if call: QThread.sleep(5)
self.signals.srv_status.emit(call)
self.signals.srv_running.emit(False)
class Test(QWidget):
def __init__(self):
super(Test, self).__init__()
self.initUI()
def initUI(self):
layout = QHBoxLayout(self)
self.cb = QPushButton('Send request', self)
self.cb.clicked.connect(self.srv_send)
layout.addWidget(self.cb)
self.lbl = QLabel('Waiting...', self)
layout.addWidget(self.lbl)
self.srv = ServiceCall()
self.srv.setAutoDelete(False)
self.srv.signals.srv_status.connect(self.srv_receive)
self.srv.signals.srv_running.connect(self.srv_block)
self.tp = QThreadPool(self)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('QRunnable and ROS service calls')
self.show()
@pyqtSlot()
def srv_send(self):
print('Main Thread ID: %d' % int(QThread.currentThreadId()))
self.tp.start(self.srv)
self.cb.setText('Running for reply')
@pyqtSlot(bool)
def srv_block(self, state):
self.cb.setEnabled(not state)
@pyqtSlot(bool)
def srv_receive(self, srv_res):
if srv_res: self.lbl.setText('Success')
else: self.lbl.setText('Failed')
self.cb.setText('Send request')
def main():
app = QApplication(argv)
t = Test()
exit(app.exec_())
if __name__ == '__main__':
main()
文档中的引用是否意味着我做错了?如果我将QThreadPool
并在我的运行中使用tryStart(self)
,我会运行很多很多线程......
【问题讨论】:
但是你禁用了autoDelete
:所以你有什么不明白的?
文档说 tryStart()
应该放在 QRunnable
的 run()
内,这不是我在这里的做法(请参阅我的帖子的最后一句话,当我放tryStart(self)
在我的run()
中)。
我认为您误解了它 - 请参阅我的回答。
【参考方案1】:
文档说它支持在run()
内调用tryStart
,而不是必需。
如果您在run()
之外按顺序调用start()
,它将重新使用同一个线程。但是如果你在run()
中调用tryStart()
,它可能会在必要时保留额外的线程。
【讨论】:
啊,我确实误解了文档。谢谢!我很高兴我的代码实际上是正确的。哈哈【参考方案2】:您需要.setAutoDelete(0)
才能使用trystart()
。
Autodelete(0)
表示线程执行后不会自动删除,需要手动删除。
然后,当使用trystart()
而不是start()
启动/重新启动线程时,会避免竞争条件,因为同一线程会继续。
它在文档上。
祝你好运
【讨论】:
以上是关于重用 QRunnable的主要内容,如果未能解决你的问题,请参考以下文章