Issue
I have been experimenting with QRunnable
in order to get some service calls up and running. I have stumbled across the following piece of information from the Qt documentation:
QThreadPool supports executing the same QRunnable more than once by calling tryStart(this) from within QRunnable::run(). If autoDelete is enabled the QRunnable will be deleted when the last thread exits the run function. Calling start() multiple times with the same QRunnable when autoDelete is enabled creates a race condition and is not recommended.
Can someone explain what this means? I've written the following code and it allows me to execute a QRunnable
object multiple times sequentially:
#!/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()
Does the quote from the documentation mean that I'm doing it wrong? If I put my QThreadPool
and use tryStart(self)
inside my run I get many, many threads running...
Solution
The documentation is saying that it supports calling tryStart
inside run()
, not that it is required.
If you sequentially call start()
outside of run()
it will re-use the same thread. But if you call tryStart()
within run()
it may reserve additional threads if necessary.
Answered By - ekhumoro
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.