QThread源码浅析[通俗易懂]

QThread源码浅析[通俗易懂]Qt版本Qt5.6.0,下面以Windows平台为例简单研究下QThread源码实现。1.仅研究下QThread::start()函数,其他细节在次不涉及:src\qtbase\src\corelib\thread\qthread_win.cppvoidQThread::start(Prioritypriority){Q_D(QThread);QMutexLocker…

大家好,又见面了,我是你们的朋友全栈君。

Qt版本 Qt5.6.0,下面以Windows平台为例简单研究下QThread源码实现。

1.仅研究下QThread::start()函数,其他细节在次不涉及:

src\qtbase\src\corelib\thread\qthread_win.cpp

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.挑出里面的重点:

#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,来看下这个函数的几个参数:

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 :

src\qtbase\src\corelib\thread\qthread_win.cpp

// 参数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.net/140342.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月28日 下午12:36
下一篇 2022年5月28日 下午12:46


相关推荐

  • 给你的wordpress博客中加入喜欢的鼠标指针

    想给你的博客加个喜欢的鼠标指针吗?其实很简单的,wordpress中要加入只需修改皮肤中的css。在body中插入cursor:url(‘鼠标指针网址’)}就可以了,如果想修改鼠标指针接触到链接的鼠标样式,那只要在a中插入cursor:url(‘鼠标指针网址’),我用的是个企鹅,挺好玩的。我也发上来,喜欢的可以用用。鼠标指针转载于:https://www.cnblogs.com/joyp…

    2022年4月12日
    55
  • 程序员必看!从零开始手把手教你用Coze搭建智能体(附完整教程)

    程序员必看!从零开始手把手教你用Coze搭建智能体(附完整教程)

    2026年3月12日
    2
  • 数学建模-二胎政策对中国人口的影响[通俗易懂]

    数学建模-二胎政策对中国人口的影响[通俗易懂]  研一的数学建模课上的关于“二胎政策对中国人口的影响”。研究中国人口,发现中国人口老龄化非常严重,如今假设不放开全面二胎,那么中国的未来真的非常令人堪忧。事实上,如今的单独二胎对人口的影响不是太多,每年添加100多万的人口,对于中国日益下降的人口增长率影响根本不大。   首先,本文通过搜集第六次人口普查的资料,将中国人口依照年龄组(5岁为一个年龄组)分为21个组,实行单独…

    2025年9月8日
    8
  • phpstorm-2021.5.1激活码【在线注册码/序列号/破解码】「建议收藏」

    phpstorm-2021.5.1激活码【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    37
  • MATLAB之fprintf函数的具体使用方法

    MATLAB之fprintf函数的具体使用方法fprintf函数可以将数据按指定格式写入到文本文件中。其调用格式为:数据的格式化输出:fprintf(fid,format,variables)按指定的格式将变量的值输出到屏幕或指定文件fid为文件句柄,若缺省,则输出到屏幕format用来指定数据输出时采用的格式%d整数%e实数:科学计算法形式%f实数:小数形式%g由系统自动选取上述两种格式之一%s输出字符串fprintf(fid,forma…

    2022年10月19日
    5
  • docker部署web项目_docker web管理工具

    docker部署web项目_docker web管理工具前言前面我们运行的容器并没有一些什么特别的用处。接下来让我们尝试使用docker构建一个web应用程序。我们将在docker容器中运行一个PythonFlask应用来运行一个web

    2022年7月31日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号