大家好,又见面了,我是你们的朋友全栈君。
Qt版本 Qt5.6.0,下面以Windows平台为例简单研究下QThread源码实现。
1.仅研究下QThread::start()函数,其他细节在次不涉及:
srcqtbasesrccorelibthreadqthread_win.cpp
代码语言:javascript复制void QThread::start(Priority priority)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (d->isInFinish) {
locker.unlock();
wait();
locker.relock();
}
if (d->running)
return;
... ... // d指针配置
#ifndef Q_OS_WINRT
... ... // 注释
d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
this, CREATE_SUSPENDED, &(d->id));
#else // !Q_OS_WINRT
d->handle = (Qt::HANDLE) CreateThread(NULL, d->stackSize, (LPTHREAD_START_ROUTINE)QThreadPrivate::start,
this, CREATE_SUSPENDED, reinterpret_cast<LPDWORD>(&d->id));
#endif // Q_OS_WINRT
if (!d->handle) {
qErrnoWarning(errno, "QThread::start: Failed to create thread");
d->running = false;
d->finished = true;
return;
}
int prio;
d->priority = priority;
switch (d->priority) {
... ... // 线程优先级配置
case InheritPriority:
default:
prio = GetThreadPriority(GetCurrentThread());
break;
}
if (!SetThreadPriority(d->handle, prio)) {
qErrnoWarning("QThread::start: Failed to set thread priority");
}
if (ResumeThread(d->handle) == (DWORD) -1) {
qErrnoWarning("QThread::start: Failed to resume new thread");
}
}
2.挑出里面的重点:
代码语言:javascript复制#ifndef Q_OS_WINRT
d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
this, CREATE_SUSPENDED, &(d->id));
#else // !Q_OS_WINRT
d->handle = (Qt::HANDLE) CreateThread(NULL, d->stackSize, (LPTHREAD_START_ROUTINE)QThreadPrivate::start,
this, CREATE_SUSPENDED, reinterpret_cast<LPDWORD>(&d->id));
#endif // Q_OS_WINRT
3.看到了Windows下创建线程的函数 _beginthreadex,来看下这个函数的几个参数:
代码语言:javascript复制unsigned long _beginthreadex(
void *security, // 安全属性,NULL为默认安全属性
unsigned stack_size, // 指定线程堆栈的大小。如果为0,则线程堆栈大小和创建它的线程的相同。一般用0
unsigned ( __stdcall *start_address )( void * ),
// 指定线程函数的地址,也就是线程调用执行的函数地址(用函数名称即可,函数名称就表示地址)
void *arglist, // 传递给线程的参数的指针,可以通过传入对象的指针,在线程函数中再转化为对应类的指针
unsigned initflag, // 线程初始状态,0:立即运行;CREATE_SUSPEND:suspended(悬挂)
unsigned *thrdaddr // 用于记录线程ID的地址
);
4.参数 start_address 和 arglist 是线程创建的重点,对应QThread::start中的代码看下:
start_address — QThreadPrivate::start
arglist — this 指针,也就是QThread或者其派生类对象本身
5.接下来看下QThreadPrivate::start :
srcqtbasesrccorelibthreadqthread_win.cpp
代码语言:javascript复制// 参数arg其实为QThread对象的this指针
unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg)
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
// 创建线程局部存储变量,存放线程id
qt_create_tls();
TlsSetValue(qt_current_thread_data_tls_index, data);
data->threadId = reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
QThread::setTerminationEnabled(false);
{
QMutexLocker locker(&thr->d_func()->mutex);
data->quitNow = thr->d_func()->exited;
}
if (data->eventDispatcher.load()) // custom event dispatcher set?
data->eventDispatcher.load()->startingUp();
else
createEventDispatcher(data);
... ...
emit thr->started(QThread::QPrivateSignal()); // 发射线程启动信号
QThread::setTerminationEnabled(true);
thr->run(); // 调用QThread::run()虚函数 -- 线程函数
finish(arg);
return 0;
}
终于看到QThread::run虚函数是在哪儿调用的,也看到了QThread::started信号是在哪儿发射的!
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/140342.html原文链接:https://javaforall.cn