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

Reply via email to