[PyKDE] Using thread and event filter crashes Python

Yann Cointepas yann at sapetnioc.org
Mon Jul 11 16:50:27 BST 2005


On Sunday 10 July 2005 19:44, you wrote:
>
> With current snapshots I don't get the double delete and get a SIGKILL
> rather than a seg fault.
>
> The above code definately breaks Qt's rules - you must must create QWidgets
> in the main GUI thread. I need another example that demonstrate's the
> problem but conforms to Qt's rules.
>
> Phil

I thought it was legal to create widgets in any thread between qt.qApp.lock() 
and qt.qApp.lock(). I used this to make a smaller example.

The error is still here with legal code. I joined a modification of the program 
that uses a queue of functions which are called from the main GUI thread via 
a QTimer. It produces exactly the same error as the previous sample code but 
uses Qt only from the main thread.

I noticed a different behavior for two different python/sip versions. With 
Fedora core 2 versions (Python 2.3.3/sip 3.10.1/Qt 3.3.3), I have the
following output:

!threadedFunction! <Thread(Thread-1, started)>
!createWidget! <_MainThread(MainThread, started)>
!init TestWidget! <_MainThread(MainThread, started)>
!del TestWidget! <_MainThread(MainThread, started)>
python: Objects/classobject.c:631: instance_dealloc: Assertion `g->gc.gc_refs != (-2)' failed.
Abort


With my own Python/sip/PyQt compiled from sources 
(Python 2.4.1/sip 4.2.1/qt 3.3.3), the result is:

!threadedFunction! <Thread(Thread-1, started)>
!createWidget! <_MainThread(MainThread, started)>
!init TestWidget! <_MainThread(MainThread, started)>
!del TestWidget! <_MainThread(MainThread, started)>
!del TestWidget! <_MainThread(MainThread, started)>
Segmentation fault

#----------------------------------------------------------------------------
import sys, threading
from qt import *

class EventFilter( QObject ):
  def eventFilter( self, o, e ):
    return False

class TestWidget( QWidget ):
  def __init__( self ):
    print '!init TestWidget!', threading.currentThread()
    QWidget.__init__( self )

  def __del__( self ):
    print '!del TestWidget!', threading.currentThread()


class MainThreadActions( QObject ):
  '''Queue of functions that are called from the main thread
  via a QTimer. Functions and arguments can be pushed in 
  the queue (from any thread) with the push method.'''
  def __init__( self, parent = None ):
    QObject.__init__( self, parent )
    self.lock = threading.RLock()
    self.actions = []
    self.timer = QTimer( self )
    self.connect( self.timer, SIGNAL( 'timeout()' ), self.__doAction )
    self.timer.start( 100, 0 )

  def push( self, function, *args, **kwargs ):
    self.lock.acquire()
    try:
      self.actions.append( ( function, args, kwargs ) )
    finally:
      self.lock.release()

  def __doAction( self ):
    self.lock.acquire()
    try:
      actions = self.actions
      self.actions = []
    finally:
      self.lock.release()
    for ( function, args, kwargs ) in actions:
      if kwargs is None or len( kwargs ) == 0:
        apply( function, args )
      else:
        apply( function, args, kwargs )


def threadedFunction():
  '''This function is *not* called from the main GUI thread'''
  print '!threadedFunction!', threading.currentThread()
  mainThread.push( createWidget )


def createWidget():
  '''This function is called from the main GUI thread'''
  print '!createWidget!', threading.currentThread()
  w = TestWidget()
  w.show()
  del w


app = QApplication( sys.argv )

theEventFilter = EventFilter()
qApp.installEventFilter( theEventFilter )

mainThread = MainThreadActions()

mainWindow = QLabel( 'main', None )
mainWindow.show()
app.setMainWidget( mainWindow )

t = threading.Thread( target=threadedFunction )
t.start()

app.exec_loop()


-- 
Yann Cointepas                         Tel: +33 1 69 86 78 52
CEA - SHFJ                             Fax: +33 1 69 86 77 86
4, place du General Leclerc
91401 Orsay Cedex France




More information about the PyQt mailing list