[PyKDE] PyQt 3.12 introduces race condition/deadlock with QApplication.postEvent.

Truls A. Tangstad kerfue+pykde at herocamp.org
Tue Aug 10 09:57:01 BST 2004


On Fri, Aug 06, 2004 at 12:54:53PM +0200, Truls A. Tangstad wrote:
> We've had a lot of problems with our application (SciCraft[1]) hanging
> at odd times after upgrading to PyQt 3.12 (package python2.3-qt3) in
> debian.  The problem seems to occur whenever we do a postEvent from
> another thread while the event/gui-thread is handling a previous
> event. Using PyQt 3.12 the application deadlocks when posting the
> second event, while using version 3.11 gives none of these problems.
> 
> Attached is an example script showing the problem. The script runs
> successfully (for me) using 3.11 and hangs on postEvent in 3.12. The
> script uses a custom event with a data object with a slow __del__ to
> make sure that the event handling is stalled long enough for the
> second postEvent to occur.
> 
> Does anyone know a workaround, fix or even a kludge for this problem?

Just to reply to my own mail, in case anyone else has a similar
problem, i'm posting a hack we've done around the problem, but it's
not a nice hack, and I'm very much hoping the problem with postEvent
will be fixed.

What we ended up doing was creating a threadsafe Queue object (from
module Queue in python) handling objects passed between threads.
Instead of using postEvent to send a QCustomEvent with user data to
the eventthread, we used a QTimer.singleShot(0, target.processEvents)
where target might have an implementation like the following:

from qt import QWidget, qApp, QTimer, QPaintEvent, QRect
from Queue import Queue, Empty
class Target(QWidget):
    def __init__(self):
        self._unprocessedEvents = Queue

    def addEvent(self, event):
        self._unprocessedEvents.put(event)
	
    def processEvents(self):
        while 1:
	    event = self._unprocessedEvents.get_nowait()
	    self.doGuiStuffWithEvent(event)
	except Empty:
	    pass

    def doGuiStuffWithEvent(self, event)
        ...


    def handleEventFromOtherThread(self, event):
        self._unprocessedEvents.put(event)
	QTimer.singleShot(0, self.processEvents)
	# force awakening of eventthread due to
	# other bug in python-qt
	qt.qApp.postEvent(self, QPaintEvent(QRect(0,0,0,0)))
        

The event object used here is application specific data and not
an object from a QEvent subclass. To post an event from another thread
and trigger the event handling, you just call
target.handleEventFromOtherThread(myEvent) from any object which will
then add it to the objects own event-queue then trigger the
eventthread which starts the handling of all waiting events.
QTimer.singleShot is used to simulated postEvent, but since it can't
send parameters, we use the Queue. 

As commented in the code, we use postEvent with a QPaintEvent just to
force the event thread to wake up. As far as I know this is not a
problem in Qt, but PyQt. In my applications I seem to have to move the
mouse around the application to wake up the event thread when using
QTimers from other threads. Using a dummy postEvent atleast forces the
event thread to wake up.

IMPORTANT: 
This is just a hack to get around a problem with postEvent with
QCustomEvent in PyQt 3.12 and is only posted for those interested in a
very temporary hack.

I'm would also be interested to know if anyone else has the same
problem with PyQt 3.12 as explained in my original post, or if this is
a debian specific problem.

-- 
Truls A. Tangstad - <kerfue+pykde at h e r o c a m p.org>




More information about the PyQt mailing list