diff options
author | Olivier Goffart <ogoffart@trolltech.com> | 2009-05-18 20:35:42 (GMT) |
---|---|---|
committer | Olivier Goffart <ogoffart@trolltech.com> | 2009-05-20 14:18:03 (GMT) |
commit | 4a756726ee874ff2ce496e1b113707c65c39a76b (patch) | |
tree | 696710e189af90dc6ac19cac2887e779e4257c71 /tests | |
parent | efb14d56ef9cd327f6358f626f79e3ee88078600 (diff) | |
download | Qt-4a756726ee874ff2ce496e1b113707c65c39a76b.zip Qt-4a756726ee874ff2ce496e1b113707c65c39a76b.tar.gz Qt-4a756726ee874ff2ce496e1b113707c65c39a76b.tar.bz2 |
Use a per object lock for signal/slots
That way we prevent the current possible race condition that may appears
while touching signals slot while object are moved to different threads.
For exemple, when we do sender->threadData->mutex->lock(); the sender
can possibly be moved to another thread between the moment we get the
pointer to the threadData and the moment we aquire the lock. We could
check if we locked the right mutex and retry otherwise, but that would
break if the threadData (and hence the mutex) get destroyed in between.
The per object mutex is implemented with a thread pool.
I'm not using the global QThreadPool because we might ends up locking
two of their mutex, and that would be dangerous if something else holds
a lock on the same mutex (possible deadlock)
Putting the mutex pool in a Q_GLOBAL_STATIC doesn't work as it might
result of the ppol being deleted before some other object in others
Q_GLOBAL_STATIC structures
There is no need to lock this mutex in moveToThread as this is safe.
When emiting a signal, we do not need to lock the thread data, as the
user must ensure that the object is not moved to a thread while emiting
a AutoConnection signal.
Reviewed-by: Brad
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qobjectrace/tst_qobjectrace.cpp | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/tests/auto/qobjectrace/tst_qobjectrace.cpp b/tests/auto/qobjectrace/tst_qobjectrace.cpp index fcfd528..aa80534 100644 --- a/tests/auto/qobjectrace/tst_qobjectrace.cpp +++ b/tests/auto/qobjectrace/tst_qobjectrace.cpp @@ -43,6 +43,7 @@ #include <QtCore> #include <QtTest/QtTest> + enum { OneMinute = 60 * 1000, TwoMinutes = OneMinute * 2 }; class tst_QObjectRace: public QObject @@ -70,12 +71,18 @@ public: public slots: void theSlot() { - enum { step = 1000 }; + enum { step = 35 }; if ((++count % step) == 0) { QThread *nextThread = threads.at((count / step) % threads.size()); moveToThread(nextThread); } } + + void destroSlot() { + emit theSignal(); + } +signals: + void theSignal(); }; class RaceThread : public QThread @@ -120,6 +127,10 @@ private slots: if (stopWatch.elapsed() >= OneMinute / 2) #endif quit(); + + QObject o; + connect(&o, SIGNAL(destroyed()) , object, SLOT(destroSlot())); + connect(object, SIGNAL(destroyed()) , &o, SLOT(deleteLater())); } }; @@ -138,10 +149,17 @@ void tst_QObjectRace::moveToThreadRace() for (int i = 0; i < ThreadCount; ++i) threads[i]->start(); - QVERIFY(threads[0]->wait(TwoMinutes)); + + while(!threads[0]->isFinished()) { + QPointer<RaceObject> foo (object); + QObject o; + connect(&o, SIGNAL(destroyed()) , object, SLOT(destroSlot())); + connect(object, SIGNAL(destroyed()) , &o, SLOT(deleteLater())); + QTest::qWait(10); + } // the other threads should finish pretty quickly now for (int i = 1; i < ThreadCount; ++i) - QVERIFY(threads[i]->wait(30000)); + QVERIFY(threads[i]->wait(300)); for (int i = 0; i < ThreadCount; ++i) delete threads[i]; |