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:
parent
422b6ba9ec
commit
b067f6cfe3
@ -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
|
||||
*/
|
||||
|
@ -96,6 +96,7 @@ class Q_CORE_EXPORT QEventLoopLocker
|
||||
public:
|
||||
QEventLoopLocker();
|
||||
explicit QEventLoopLocker(QEventLoop *loop);
|
||||
explicit QEventLoopLocker(QThread *thread);
|
||||
~QEventLoopLocker();
|
||||
|
||||
private:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user