summaryrefslogtreecommitdiffstats
path: root/tests/auto/qobject
diff options
context:
space:
mode:
authorBradley T. Hughes <bradley.hughes@nokia.com>2010-10-29 15:04:46 +0200
committerBradley T. Hughes <bradley.hughes@nokia.com>2010-10-29 16:02:16 +0200
commit0c643b179c5154c50b61dba421016b7b48794720 (patch)
treeee7c2f59dd970d90d7c546ac52e6cd801898280d /tests/auto/qobject
parente7b9fb2e87641a36301babf457056b3350f0431c (diff)
Simplify object lifetime management when moving objects to a QThread
The documentation for Qt::AutoConnection states is a signal is emitted from the same thread as the receiving object, the connection should behave as Qt::DirectConnection. The actual behavior prior to this commit was different from the documentation; if the signal was emitted in a thread different from the sender's thread, then we would queue (which is now corrected). By making the behavior match the documentation, it is now possible to connect QThread's finished() signal to an object's deleteLater() slot and the slot will execute when finished() is emitted (previously it was queued). QObject::deleteLater() uses a posted QEvent::DeferredDelete event to trigger deletion of the object. In QThread, after emitting the finished() signal, we now send all pending DeferredDelete events to ensure that all pending deletions happen. We have precedence for this behavior, QCoreApplication::exec() does the same thing after emitting the aboutToQuit() signal. Reviewed-by: joao Reviewed-by: olivier
Diffstat (limited to 'tests/auto/qobject')
-rw-r--r--tests/auto/qobject/tst_qobject.cpp78
1 files changed, 78 insertions, 0 deletions
diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp
index 24cd5a35e1..a09f109e1c 100644
--- a/tests/auto/qobject/tst_qobject.cpp
+++ b/tests/auto/qobject/tst_qobject.cpp
@@ -134,6 +134,7 @@ private slots:
void connectConstructorByMetaMethod();
void disconnectByMetaMethod();
void disconnectNotSignalMetaMethod();
+ void autoConnectionBehavior();
protected:
};
@@ -3847,5 +3848,82 @@ void tst_QObject::disconnectNotSignalMetaMethod()
QVERIFY(!QObject::disconnect(&s, slot, &r, QMetaMethod()));
}
+class ThreadAffinityThread : public QThread
+{
+public:
+ SenderObject *sender;
+
+ ThreadAffinityThread(SenderObject *sender)
+ : sender(sender)
+ { }
+ void run()
+ {
+ sender->emitSignal1();
+ }
+};
+
+void tst_QObject::autoConnectionBehavior()
+{
+ SenderObject *sender = new SenderObject;
+ ReceiverObject *receiver = new ReceiverObject;
+ connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1()));
+
+ // at emit, currentThread == sender->thread(), currentThread == receiver->thread(), sender->thread() == receiver->thread()
+ QVERIFY(!receiver->called(1));
+ sender->emitSignal1();
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() == receiver->thread()
+ ThreadAffinityThread emitThread1(sender);
+ QVERIFY(!receiver->called(1));
+ emitThread1.start();
+ QVERIFY(emitThread1.wait(30000));
+ QVERIFY(!receiver->called(1));
+ QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread == sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+ sender->moveToThread(&emitThread1);
+ QVERIFY(!receiver->called(1));
+ emitThread1.start();
+ QVERIFY(emitThread1.wait(30000));
+ QVERIFY(!receiver->called(1));
+ QCoreApplication::sendPostedEvents(receiver, QEvent::MetaCall);
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread == receiver->thread(), sender->thread() != receiver->thread()
+ QVERIFY(!receiver->called(1));
+ sender->emitSignal1();
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ // at emit, currentThread != sender->thread(), currentThread != receiver->thread(), sender->thread() != receiver->thread()
+ ThreadAffinityThread emitThread2(sender);
+ QThread receiverThread;
+ QTimer *timer = new QTimer;
+ timer->setSingleShot(true);
+ timer->setInterval(100);
+ connect(&receiverThread, SIGNAL(started()), timer, SLOT(start()));
+ connect(timer, SIGNAL(timeout()), &receiverThread, SLOT(quit()), Qt::DirectConnection);
+ connect(&receiverThread, SIGNAL(finished()), timer, SLOT(deleteLater()));
+ timer->moveToThread(&receiverThread);
+
+ receiver->moveToThread(&receiverThread);
+ QVERIFY(!receiver->called(1));
+ emitThread2.start();
+ QVERIFY(emitThread2.wait(30000));
+ QVERIFY(!receiver->called(1));
+ receiverThread.start();
+ QVERIFY(receiverThread.wait(30000));
+ QVERIFY(receiver->called(1));
+ receiver->reset();
+
+ delete sender;
+ delete receiver;
+}
+
QTEST_MAIN(tst_QObject)
#include "tst_qobject.moc"