qt线程套路,qt线程源码分析

qt源码地址:

https://github.com/radekp/qt/blob/b881d8fb99972f1bd04ab4c84843cc8d43ddbeed/src/corelib/thread/qthread_unix.cpp

       Qt的线程应该是大家讨论比较多的,也是迷惑比较多的。这主要和qt线程实现机制和上层封装出的接口有关,封装的不清不楚,接口要么就封装的完全不知道里面是什么东西,要么就让大家知道里面是什么,(当然前者是最正确的)新人经常犯的错误是继承了线程类意味从此这个类里面的所有东西都是线程的,单是实际上只有run方法是线程里面运行。当然还有那个movetothread,暂且我们不论。

好了回到正题贴代码:

当我们继承qt线程创建线程的时候,实际上只有到了运行start的时候才创建了线程。下面是qt源码的start

void QThread::start(Priority priority)
{
    Q_D(QThread);
    QMutexLocker locker(&d->mutex);
    if (d->running)
        return;

    d->running = true;  //线程运行标志位
    d->finished = false; // 
    d->terminated = false;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    d->priority = priority;

#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && !defined(Q_OS_SYMBIAN) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
// ### Need to implement thread sheduling and priorities for symbian os. Implementation removed for now
    switch (priority) {
 /*

qt 线程权限设置,qt封装出了自己的设置,到了具体平台,linux下就是设置qt属性

*/
    case InheritPriority:
        {
            pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
            break;
        }

    default:
        {
            int sched_policy;
            if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
                // failed to get the scheduling policy, don't bother
                // setting the priority
                qWarning("QThread::start: Cannot determine default scheduler policy");
                break;
            }

            int prio_min = sched_get_priority_min(sched_policy);
            int prio_max = sched_get_priority_max(sched_policy);
            if (prio_min == -1 || prio_max == -1) {
                // failed to get the scheduling parameters, don't
                // bother setting the priority
                qWarning("QThread::start: Cannot determine scheduler priority range");
                break;
            }

            int prio;
            switch (priority) {
            case IdlePriority:
                prio = prio_min;
                break;

            case TimeCriticalPriority:
                prio = prio_max;
                break;

            default:
                // crudely scale our priority enum values to the prio_min/prio_max
                prio = (priority * (prio_max - prio_min) / TimeCriticalPriority) + prio_min;
                prio = qMax(prio_min, qMin(prio_max, prio));
                break;
            }

            sched_param sp;
            sp.sched_priority = prio;

            if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
                || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
                || pthread_attr_setschedparam(&attr, &sp) != 0) {
                // could not set scheduling hints, fallback to inheriting them
                pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
            }
            break;
        }
    }
#endif // _POSIX_THREAD_PRIORITY_SCHEDULING

#ifdef Q_OS_SYMBIAN
    if (d->stackSize == 0)
        // The default stack size on Symbian is very small, making even basic
        // operations like file I/O fail, so we increase it by default.
        d->stackSize = 0x14000; // Maximum stack size on Symbian.
#endif

    if (d->stackSize > 0) {
#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
        int code = pthread_attr_setstacksize(&attr, d->stackSize);
#else
        int code = ENOSYS; // stack size not supported, automatically fail
#endif // _POSIX_THREAD_ATTR_STACKSIZE

        if (code) {
            qWarning("QThread::start: Thread stack size error: %s",
                     qPrintable(qt_error_string(code)));

            // we failed to set the stacksize, and as the documentation states,
            // the thread will fail to run...
            d->running = false;
            d->finished = false;
            return;
        }
    }
/*

真正创建线程,线程实体函数是 QThreadPrivate::start

*/
    int code =                        
        pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
    if (code == EPERM) {
        // caller does not have permission to set the scheduling
        // parameters/policy
#ifndef Q_OS_SYMBIAN
        pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
#endif
        code =
            pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
    }

    pthread_attr_destroy(&attr);

    if (code) {
        qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));

        d->running = false;
        d->finished = false;
        d->thread_id = 0;
#ifdef Q_OS_SYMBIAN
        d->data->symbian_thread_handle.Close();
#endif
    }
}

我们接着分析:

线程的实体 函数

void *QThreadPrivate::start(void *arg)
{
    // Symbian Open C supports neither thread cancellation nor cleanup_push.
#ifndef Q_OS_SYMBIAN
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    pthread_cleanup_push(QThreadPrivate::finish, arg);
#endif

    QThread *thr = reinterpret_cast<QThread *>(arg);
    QThreadData *data = QThreadData::get2(thr);

#ifdef Q_OS_SYMBIAN
    // Because Symbian Open C does not provide a way to convert between
    // RThread and pthread_t, we must delay initialization of the RThread
    // handle when creating a thread, until we are running in the new thread.
    // Here, we pick up the current thread and assign that to the handle.
    data->symbian_thread_handle = RThread();
    TThreadId threadId = data->symbian_thread_handle.Id();
    data->symbian_thread_handle.Open(threadId);
#endif

    pthread_once(&current_thread_data_once, create_current_thread_data_key);
    pthread_setspecific(current_thread_data_key, data);

    data->ref();
    data->quitNow = false;

    // ### TODO: allow the user to create a custom event dispatcher
    createEventDispatcher(data);

    emit thr->started();
#ifndef Q_OS_SYMBIAN
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
#endif
    thr->run();  
/* 

线程里面运行了run函数,run函数熟悉不,其实就是我们继承的线程类里面run的虚函数
归根到底,就是创建的线程里面回调了run,也就是我们自己的函数,所以说qt只有run
是在线程里面。

*/

#ifdef Q_OS_SYMBIAN
    QThreadPrivate::finish(arg);
#else
    pthread_cleanup_pop(1); 
#endif

    return 0;
}

2018年8月14日23:44:29

猜你喜欢

转载自blog.csdn.net/u013372900/article/details/81676483
今日推荐