This is one of those things I tend to forget
This is one of those things I tend to forget
Here’s some code for my future reference on how to use QMutex or QMutexLocker.
* Use QMutex to protect data, not code. Try not to lock hughe amounts of code within a function with mutex.lock(), mutex.unlock(), if for any reason you forget to release the lock you’ll be in trouble. Use the mutex directly only when you know what it is that you want to protect concurrent access from.
* When you have a complex function and you don’t want to worry about what to protect and when to release the lock (on exceptions thrown, before returns,etc), you can create an instance of QMutexLocker and it should release the mutex lock upon destruction… this takes us to the next lesson
* When using a QMutexLocker, DO NOT make the QMutexLocker an attribute of your class, otherwise, the reference will live after the method finishes and the lock won’t be released.
Here’s some code.
from PyQt4.Qt import QObject, QMutex, QApplication, QThread, QMutexLocker import sys class MutexTestSubject(QObject): ''' Class that uses a QMutex to synchronize access to its add(),substract() methods. This works perfectly fine. ''' def __init__(self): QObject.__init__(self) self.MAX_LIMIT = 100 self.MIN_LIMIT = 0 self.counter = 50 self.mutex = QMutex() def add(self): self.mutex.lock() if self.counter < self.MAX_LIMIT: self.counter = self.counter + 1 self.mutex.unlock() def substract(self): self.mutex.lock() if self.counter > self.MIN_LIMIT: self.counter = self.counter - 1 self.mutex.unlock() def printStatus(self,thread): print "Counter:",self.counter," - Thread:",id(thread) if self.counter > self.MAX_LIMIT+1 or self.counter < self.MIN_LIMIT: print "Stopping Threads, Max Surpassed, Not Thread Safe. Last Thread:",id(thread) sys.exit() class MutexLockerTestSubject(QObject): ''' Class that attemps to synchronize thread access to its add(),substract() methods with the QMutexLocker object. ''' def __init__(self): QObject.__init__(self) self.MAX_LIMIT = 100 self.MIN_LIMIT = 0 self.counter = 50 self.mutex = QMutex() def add(self): #VIP: DO NOT MAKE mutexLocker an attribute of your class. #other wise it won't be destroyed and the lock will never be released. mutexLocker = QMutexLocker(self.mutex) if self.counter < self.MAX_LIMIT: self.counter = self.counter + 1 def substract(self): mutexLocker = QMutexLocker(self.mutex) if self.counter > self.MIN_LIMIT: self.counter = self.counter - 1 def printStatus(self,thread): print "Counter:",self.counter," - Thread:",id(thread) if self.counter > self.MAX_LIMIT+1 or self.counter < self.MIN_LIMIT: print "Stopping Threads, Max Surpassed, Not Thread Safe. Last Thread:",id(thread) sys.exit() class AdderWorker(QThread): def __init__(self, mutexTestObject): self.mutexTestObject = mutexTestObject QThread.__init__(self) def run(self): while(True): self.mutexTestObject.add() self.mutexTestObject.printStatus(self) class SubstractorWorker(QThread): def __init__(self, mutexTestObject): self.mutexTestObject = mutexTestObject QThread.__init__(self,mutexTestObject) def run(self): while(True): self.mutexTestObject.substract() self.mutexTestObject.printStatus(self) if __name__ == "__main__": USE_MUTEX_LOCKER = True #switch this to use regular mutexes vd QMutexLocker app = QApplication(sys.argv) mutexTestObject = MutexTestSubject() if not USE_MUTEX_LOCKER else MutexLockerTestSubject() adderThread = AdderWorker(mutexTestObject) substracterThread = SubstractorWorker(mutexTestObject) adderThread.start() substracterThread.start() sys.exit(app.exec_())
I keep making the mistake of sending PyQt_PyObjects instead of sending actual Qt4 objects on signals that are defined by Qt like that.
If a signal has been defined by Qt, to send Qt objects, just copy and paste it, do not try to override it by exchanging the Qt objects for PyQt_PyObject.
This is because PyQt_PyObject is used to represent regular Python objects, therefore, original Qt4 classes will never emit signals under those weird signatures, Qt4 seems to be very strict on how it matches signals.
So when you see something like this on the documentation:
Qt Signals void currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)
Define your signal for example like this, and it will work:
SIGNAL_ITEM_CHANGED = SIGNAL('currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)')
Do not do this, cause it won’t work:
SIGNAL_ITEM_CHANGED = SIGNAL('currentItemChanged (PyQt_PyObject, PyQt_PyObject)')
(Keep in mind PyQt_PyObject is used to represent Python objects only, and its useful only when YOU define and emit your own signals)
then connect it from a QTreeWidget item (or derived object) to a listener object’s method like this:
Your object’s listener method should look like this:
def onItemChanged(self, current, previous): #do what you gotta do, current and previous will be QTreeWidgetItems
– Make sure you don’t have cygwin or C:devkitPromsysbin in your path,
or else your make files can end up trying to run the Makefile using ‘sh’ and all
the makefile we’re about to use are meant to run from the windows command line.
If for some odd reason you type ‘sh’ on your windows command line and you see something like:
You’re likely to find this later on:
/bin/sh: -c: line 2: syntax error: unexpected end of file
– Install Qt open source, with the exe installer, this will attempt to install
ming if you don’t have it installed, say yes, mingw rocks.
– Make sure you have the following Windows environment variables set:
QTDIR = c:Qt4.2.2
QTMAKESPEC = win32-g++
– Make sure you have Python2.5, Qt bin and Mingw bin folders on your path
PATH = %PATH%;c:Mingwbin;c:Mingwlibexecgccmingw323.4.2;c:python25bin;c:Qt4.2.2bin
– Get pexports just in case the Qt doesn’t have libQtCore4.a on its lib/
You can download pexports at:
If you don’t have that libQtCore4.a you won’t be able to build PyQt.
So you’ll need to do this, go to your Qt bin folder, say:
And run this:
pexports QtCore4.dll > Qt4Core4.def
dlltool -dllname QtCore4.dll –def QtCore4.def –output-lib libQtCore4.a
Move the resulting file, libQtCore4.a, to c:Qt4.2.2lib
– PyQt needs “sip” to be able to bind the Qt libraries, sip will generate the necessary C++ code.
To install sip, get its source code, extract it to a folder say:
Once inside run it’s configure.py like this:
python configure.py -p win32-g++
That will create the Makefiles, then you will make it using
Now, I’m not sure what’s the environment variable of Mingw library path,
and I was having errors from the compilation of PyQt, telling me it couldn’t
find the sip libraries, so this is what I did:
– Copy all the .o files from c:sip-4.5.2siplib to c:mingwlib
– Copy all the .h files from c:sip-4.5.2siplib to c:mingwincludes
– Now it’s finally time to compile PyQt.
Uncompress the PyQt zip with the source (not the binary, if not we wouldn’t be doing this),
do it at the root of your hardrive (C:), you’ll end up with a folder named similar to this:
Go in there and do this:
mingw32-make (this will take a long time, it will wrap every Qt C++ library on a new .cpp file which will be then compiled to exist as a python binding)
If you have any errors write me a comment on this post