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  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

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


[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