Add the quitlock feature to QThread.

Change-Id: Ib44ee9739499ba4c5f0fecbef3976251ea22836d
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Stephen Kelly 2012-02-08 15:55:29 +01:00 committed by Qt by Nokia
parent 422b6ba9ec
commit b067f6cfe3
6 changed files with 95 additions and 2 deletions

View File

@ -322,13 +322,19 @@ class QEventLoopLockerPrivate
{
public:
explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
: loop(loop), app(0)
: loop(loop), thread(0), app(0)
{
loop->ref();
}
explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
: loop(0), thread(thread), app(0)
{
thread->ref();
}
explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
: loop(0), app(app)
: loop(0), thread(0), app(app)
{
app->ref();
}
@ -337,12 +343,15 @@ public:
{
if (loop)
loop->deref();
else if (thread)
thread->deref();
else
app->deref();
}
private:
QEventLoopPrivate *loop;
QThreadPrivate *thread;
QCoreApplicationPrivate *app;
};
@ -390,6 +399,12 @@ QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
}
QEventLoopLocker::QEventLoopLocker(QThread *thread)
: d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
{
}
/*!
Destroys this event loop locker object
*/

View File

@ -96,6 +96,7 @@ class Q_CORE_EXPORT QEventLoopLocker
public:
QEventLoopLocker();
explicit QEventLoopLocker(QEventLoop *loop);
explicit QEventLoopLocker(QThread *thread);
~QEventLoopLocker();
private:

View File

@ -763,5 +763,14 @@ void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
}
}
bool QThread::event(QEvent *event)
{
if (event->type() == QEvent::Quit) {
quit();
return true;
} else {
return QObject::event(event);
}
}
QT_END_NAMESPACE

View File

@ -95,6 +95,8 @@ public:
QAbstractEventDispatcher *eventDispatcher() const;
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
bool event(QEvent *event);
public Q_SLOTS:
void start(Priority = InheritPriority);
void terminate();

View File

@ -60,6 +60,7 @@
#include "QtCore/qstack.h"
#include "QtCore/qwaitcondition.h"
#include "QtCore/qmap.h"
#include "QtCore/qcoreapplication.h"
#include "private/qobject_p.h"
@ -144,6 +145,7 @@ public:
~QThreadPrivate();
mutable QMutex mutex;
QAtomicInt quitLockRef;
bool running;
bool finished;
@ -179,6 +181,18 @@ public:
QThreadData *data;
static void createEventDispatcher(QThreadData *data);
void ref()
{
quitLockRef.ref();
}
void deref()
{
if (!quitLockRef.deref() && running) {
QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit));
}
}
};
#else // QT_NO_THREAD
@ -195,6 +209,9 @@ public:
static QThread *threadForId(int) { return QThread::currentThread(); }
static void createEventDispatcher(QThreadData *data);
void ref() {}
void deref() {}
Q_DECLARE_PUBLIC(QThread)
};

View File

@ -107,6 +107,8 @@ private slots:
void customEventDispatcher();
void stressTest();
void quitLock();
};
enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute };
@ -1285,5 +1287,52 @@ void tst_QThread::customEventDispatcher()
QVERIFY(weak_ed.isNull());
}
class Job : public QObject
{
Q_OBJECT
public:
Job(QThread *thread, int deleteDelay, QObject *parent = 0)
: QObject(parent), quitLocker(thread), exitThreadCalled(false)
{
moveToThread(thread);
QTimer::singleShot(deleteDelay, this, SLOT(deleteLater()));
QTimer::singleShot(1000, this, SLOT(exitThread()));
}
private slots:
void exitThread()
{
exitThreadCalled = true;
thread()->exit(1);
}
private:
QEventLoopLocker quitLocker;
public:
bool exitThreadCalled;
};
void tst_QThread::quitLock()
{
QThread thread;
QEventLoop loop;
connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
Job *job;
thread.start();
job = new Job(&thread, 500);
QCOMPARE(job->thread(), &thread);
loop.exec();
QVERIFY(!job->exitThreadCalled);
thread.start();
job = new Job(&thread, 2500);
QCOMPARE(job->thread(), &thread);
loop.exec();
QVERIFY(job->exitThreadCalled);
}
QTEST_MAIN(tst_QThread)
#include "tst_qthread.moc"