Hello Hans-Peter, Thanks for your answer! The connection type default Qt.AutoConnection should be equivalent to Qt.QueuedConnection, which in turn should be the right kind of connection to avoid race conditions. With both types, however, I do experience a race condition. With type Qt.DirectConnection on the other hand I get a runtime error
TypeError: ack() takes exactly 2 arguments (1 given) that I don't understand at the moment. I've attached a self-contained program that can be run to show the race condition (just configure the path to some large(!) image file). The output of the program is: ~ > ./racecond.py START: image.jpg RUN: image.jpg WARNING: thread not finished: image.jpg ACK: image.jpg Again, why is the WARNING printed if run() has completed execution? To quote from the documentation for QueuedConnection: "The slot is invoked when control returns to the event loop of the receiver's thread." That should give run() plenty of time to finish after emitting the signal, no? Regards Lars On Sun, Feb 26, 2012 at 10:06 PM, Hans-Peter Jansen <h...@urpla.net> wrote: > Dear Lars, > > On Sunday 26 February 2012, 15:55:25 Lars Beiderbecke wrote: >> Hello, >> >> In my application some QThreads still return isRunning() == true when >> they should be completed. >> >> More specifically, I'm using QThreads to load images asynchronously >> in the background. By emitting a signal, the thread notifies the >> main window that the pixmap has been loaded and the corresponding >> widget can be updated (code has been simplified): >> >> class ImgRequest(QtCore.QThread): >> def run(self): >> # ... load image ... >> self.emit(QtCore.SIGNAL("sigDone"), self) >> >> class MainWindow(QtGui.QMainWindow): >> self.requests = set() >> >> def request(self, filename): >> t = ImgRequest(self, filename) >> self.connect(t, QtCore.SIGNAL("sigDone"), self.ack) >> self.requests.add(t) >> t.start() >> >> def ack(self, t): >> # ... update image ... >> if t.isRunning(): >> print "WARNING: thread still running" >> t.wait() >> self.requests.remove(t) >> >> When I run above code, however, I'll often get WARNING messages, >> i.e., QThread.isRunning() is returning true even though its >> corresponding run() method has been completed. >> >> Is this merely a race condition between the signal and the actual >> completion of run(), or am I missing something fundamental about >> QThreads? Do I really need isRunning() and wait()? > > Since you don't provide a runnable snippet, all I can do is guessing: > check out the Qt.ConnectionType parameter of connect, especially > QueuedConnection and BlockingQueuedConnection, and see, if they do, > what you're after. > > While at it, please check out > http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/new_style_signals_slots.html > to further improve your code. > >> And finally, is >> there a better way to deal with the QThread objects than storing them >> in a set so that the GC won't kill them while running? > > Any scheme, that keeps the thread object reference alive, is fine. > BTW, the definition of your requests object is wrong. Either initialize > it as an instance variable in __init__ or any subsequent method, or as > a class variable omitting self. For the sake of clean code, I would > prefer the latter, even in the light of a single instance QMainWindow. > Finally, you should limit the number of threads to a sane maximum. > > Pete > _______________________________________________ > PyQt mailing list PyQt@riverbankcomputing.com > http://www.riverbankcomputing.com/mailman/listinfo/pyqt
#!/usr/bin/python import sys from PyQt4 import QtGui, QtCore IMG_FILE = "image.jpg" class MainWindow(QtGui.QMainWindow): def __init__(self, argv): QtGui.QMainWindow.__init__(self) self.store = ImgStore(self) self.store.request(IMG_FILE) class ImgRequest(QtCore.QThread): def __init__ (self, name): QtCore.QThread.__init__(self) self.name = name def run(self): print "RUN:", self.name qi = QtGui.QImage(self.name) self.emit(QtCore.SIGNAL("sigDone"), self) class ImgStore: def __init__(self, ui): self.ui = ui self.requests = set() def request(self, name): t = ImgRequest(name) self.ui.connect(t, QtCore.SIGNAL("sigDone"), self.ack, QtCore.Qt.QueuedConnection) # self.ui.connect(t, QtCore.SIGNAL("sigDone"), self.ack, QtCore.Qt.DirectConnection) self.requests.add(t) print "START:", t.name t.start() def ack(self, t): if t.isRunning(): print "WARNING: thread not finished:", t.name t.wait() self.requests.remove(t) print "ACK:", t.name if __name__ == '__main__': qapp = QtGui.QApplication(sys.argv) main = MainWindow(sys.argv) main.show() sys.exit(qapp.exec_())
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt