[PyQt] isRunning() returns true after QThread completion

Lars Beiderbecke lars.beiderbecke at googlemail.com
Tue Feb 28 20:08:46 GMT 2012


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 <hpj at 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 at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
-------------- next part --------------
A non-text attachment was scrubbed...
Name: racecond.py
Type: text/x-python
Size: 1183 bytes
Desc: not available
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20120228/04df6741/attachment.py>


More information about the PyQt mailing list