简介
QThreadData是用于表示线程相关的数据,在QObjectPrivate,QThreadPrivate中有使用,并且信号槽机制中也会用到该数据
QObjectPrivate
在创建QObject时,会赋值QObjectPrivate的threadData
QObject::QObject(QObject *parent)
: d_ptr(new QObjectPrivate)
{
....
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
......
}
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
......
Q_D(QObject);
d_ptr->q_ptr = this;
d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
d->threadData->ref();
.....
}
QThreadPrivate
QThreadPrivate的成员有QThreadData *data
在创建线程时,会设置data的thread为自己
QThread::QThread(QObject *parent)
: QObject(*(new QThreadPrivate), parent)
{
Q_D(QThread);
// fprintf(stderr, "QThreadData %p created for thread %p\n", d->data, this);
d->data->thread = this;
}
QThread::QThread(QThreadPrivate &dd, QObject *parent)
: QObject(dd, parent)
{
Q_D(QThread);
// fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
d->data->thread = this;
}
QThreadData
定义为
class QThreadData
{
public:
......
int loopLevel;
int scopeLevel;
QStack<QEventLoop *> eventLoops;
QPostEventList postEventList;
QAtomicPointer<QThread> thread;
QAtomicPointer<void> threadId;
QAtomicPointer<QAbstractEventDispatcher> eventDispatcher;
QVector<void *> tls;
FlaggedDebugSignatures flaggedSignatures;
bool quitNow;
bool canWait;
bool isAdopted;
bool requiresCoreApplication;
};
其成员有
- postEventList:事件队列
- thread:所属线程
- threadId:线程id
- eventDispatcher:线程的事件分发器
- eventLoops:事件循环
QEventLoop调用exec时,会通过LoopReference的构造函数将当前事件循环添加到eventLoops,exec退出时,在LoopReference的析构函数中将当前事件循环从eventLoops弹出
struct LoopReference {
QEventLoopPrivate *d;
QMutexLocker &locker;
bool exceptionCaught;
LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
{
d->inExec = true;
d->exit.storeRelease(false);
++d->threadData->loopLevel;
d->threadData->eventLoops.push(d->q_func());
locker.unlock();
}
~LoopReference()
{
if (exceptionCaught) {
qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
"exceptions from an event handler is not supported in Qt.\n"
"You must not let any exception whatsoever propagate through Qt code.\n"
"If that is not possible, in Qt 5 you must at least reimplement\n"
"QCoreApplication::notify() and catch all exceptions there.\n");
}
locker.relock();
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
Q_UNUSED(eventLoop); // --release warning
d->inExec = false;
--d->threadData->loopLevel;
}
};
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
//we need to protect from race condition with QThread::exit
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread.loadAcquire()))->mutex);
if (d->threadData->quitNow)
return -1;
if (d->inExec) {
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
return -1;
}
......
LoopReference ref(d, locker);
// remove posted quit events when entering a new event loop
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit);
#ifdef Q_OS_WASM
// Partial support for nested event loops: Make the runtime throw a JavaSrcript
// exception, which returns control to the browser while preserving the C++ stack.
// Event processing then continues as normal. The sleep call below never returns.
// QTBUG-70185
if (d->threadData->loopLevel > 1)
emscripten_sleep(1);
#endif
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
ref.exceptionCaught = false;
return d->returnCode.loadRelaxed();
}