Hi all,
What's the best way to pause and resume processing in QThread objects?
I've built a small test app that sets up a Python os.walk() process
that I'd like to be able to pause and restart from where it left off.
The documentation on QWaitCondition looks promising, though my app
appears to hang on this line (line 69):
self.condition.wait(self.mutex)
Also, in testing for a paused job in my processing method (line 104),
does a waiting thread resume from where it left off? Or do I need to
keep track of where it is myself and restart it from there?
Thanks in advance!
Scott
#!/usr/bin/env python
import sys, os
from os.path import join, getsize
from PyQt4 import QtCore, QtGui
#-------------------------------------------------------------------------------
# class
#-------------------------------------------------------------------------------
class Runner(QtCore.QThread):
def __init__(self, lock, parent=None):
QtCore.QThread.__init__(self)
self.lock = lock
self.stopped = False
self.mutex = QtCore.QMutex()
self.completed = False
self.restart = False
self.condition = QtCore.QWaitCondition()
self.rootDir = ""
def initialize(self):
self.stopped = False
self.completed = False
self.restart = False
def run(self):
self.runTask()
self.stop()
self.emit(QtCore.SIGNAL("finished(bool)"), self.completed)
def OLD_stop(self):
print "Runner.OLD_stop() ..."
try:
self.mutex.lock()
self.stopped = True
finally:
self.mutex.unlock()
def stop(self):
print "Runner.NEW_stop() ..."
with QtCore.QMutexLocker(self.mutex):
self.stopped = True
def pause(self):
# restart paused job
if self.restart:
print "self.condition.wakeOne()"
self.condition.wakeOne()
# pause running job
else:
print "self.condition.wait()"
self.condition.wait(self.mutex)
def isPaused(self):
try:
self.mutex.lock()
return self.restart
finally:
self.mutex.unlock()
def isStopped(self):
try:
self.mutex.lock()
return self.stopped
finally:
self.mutex.unlock()
def runTask(self):
progressStr = ""
if self.isStopped():
return
# set walk dir
for root, dirs, files in os.walk(self.rootDir):
if self.isStopped():
return
# resume processing???
# if self.isPaused():
# return
try:
theSum = sum(getsize(join(root, name)) for name in files),
lenFiles = len(files)
progressStr = "%s consumes: %d bytes in %d non-directory files" % (root, theSum[0], lenFiles)
except OSError:
pass
# self.emit(QtCore.SIGNAL("setProgress(string)"), progressStr)
self.emit(QtCore.SIGNAL("setProgress(PyQt_PyObject)"), progressStr)
# completed
self.completed = True
return 0
def setRootDir(self, theDir):
self.rootDir = theDir
#-------------------------------------------------------------------------------
# class
#-------------------------------------------------------------------------------
class ThreadTest(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self)
self.rootLabel = QtGui.QLabel(self.tr("Root Dir"))
self.rootEdit = QtGui.QLineEdit()
self.rootLayout = QtGui.QHBoxLayout()
self.rootLayout.addWidget(self.rootLabel)
self.rootLayout.addWidget(self.rootEdit)
self.startButton = QtGui.QPushButton(self.tr("Start"))
self.pauseButton = QtGui.QPushButton(self.tr("Pause"))
self.stopButton = QtGui.QPushButton(self.tr("Stop"))
self.buttonLayout = QtGui.QHBoxLayout()
self.buttonLayout.addWidget(self.startButton)
self.buttonLayout.addWidget(self.pauseButton)
self.buttonLayout.addWidget(self.stopButton)
self.formLayout = QtGui.QHBoxLayout()
self.formLayout.addLayout(self.rootLayout)
self.formLayout.addLayout(self.buttonLayout)
self.setLayout(self.formLayout)
# signals/slots
# ------------------------------------------------
self.startButton.clicked.connect(self.startTask)
self.pauseButton.clicked.connect(self.pauseTask)
self.stopButton.clicked.connect(self.stopTask)
# init runner object
# ------------------------------------------------
self.lock = QtCore.QReadWriteLock()
self.runner = Runner(self.lock, self)
# self.connect(self.runner, QtCore.SIGNAL("setProgress(string)"), self.setProgress)
self.connect(self.runner, QtCore.SIGNAL("setProgress(PyQt_PyObject)"), self.setProgress)
self.connect(self.runner, QtCore.SIGNAL("finished(bool)"), self.finished)
def setProgress(self, theString):
print "setProgress: ", theString
def finished(self, theBool):
print "finished: ", theBool
def startTask(self):
self.runner.setRootDir(str(self.rootEdit.text()))
self.runner.start()
def pauseTask(self):
if self.pauseButton.text() == "Pause":
self.pauseButton.setText("Resume")
else:
self.pauseButton.setText("Pause")
self.runner.pause()
def stopTask(self):
if self.runner.isRunning():
self.runner.stop()
#-------------------------------------------------------------------------------
# main
#-------------------------------------------------------------------------------
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
form = ThreadTest()
form.setWindowTitle("Thread Test")
form.show()
sys.exit(app.exec_())
_______________________________________________
PyQt mailing list [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt