Re: [PyQt] isRunning() returns true after QThread completion

2012-03-05 Thread Hans-Peter Jansen
On Tuesday 28 February 2012, 21:08:46 Lars Beiderbecke wrote:
 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.

Correct.

 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?

No, signals do not serialize in that way, they only make sure to run in 
the right context.

What you seem to be after is:

connect the finished signal in your ImgRequest class to a helper method, 
from where you emit sigDone. Now, your signals are serialized with the 
finished threads. 

Again, new style signals trump, just derive your emitting classes from a 
QObject descendant (QThread is), define your own signal with:

sigDone = QtCore.pyqtSignal(QtCore.QThread)

and emit with

self.sigDone.emit(self)

Pete
___
PyQt mailing listPyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt


Re: [PyQt] isRunning() returns true after QThread completion

2012-02-28 Thread Lars Beiderbecke
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 listPyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

[PyQt] isRunning() returns true after QThread completion

2012-02-26 Thread Lars Beiderbecke
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()?  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?

Regards
Lars
___
PyQt mailing listPyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt


Re: [PyQt] isRunning() returns true after QThread completion

2012-02-26 Thread Hans-Peter Jansen
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 listPyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt