[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