This article singled out QThread Some key codes in the source code are used to illustrate QThread How to schedule the process from start to end . Second, because it's time to Qt4.4 edition ,Qt The multithreading changes , So this chapter will use Qt4.0.1 and Qt5.6.2 Version of the original code to analyze . # QThread Class definition source code Qt4.0.1 Version source code : ```cpp #ifndef QT_NO_THREAD class Q_CORE_EXPORT QThread : public QObject { public: ...// Omit explicit QThread(QObject *parent = 0); ~QThread(); ...// Omit void exit(int retcode = 0); public slots: void start(QThread::Priority = InheritPriority); // Start thread function void terminate(); // Force exit thread function void quit(); // Thread exit function ...// Omit signals: void started(); // Thread start signal void finished(); // Thread end signal ...// Omit protected: virtual void run() = 0; int exec(); ...// Omit }; #else // QT_NO_THREAD ``` Qt5.6.2 Version source code : ```cpp #ifndef QT_NO_THREAD class Q_CORE_EXPORT QThread : public QObject { Q_OBJECT public: ...// Omit explicit QThread(QObject *parent = Q_NULLPTR); ~QThread(); ...// Omit void exit(int retcode = 0); // Thread exit function ...// Omit public Q_SLOTS: void start(Priority = InheritPriority); // Start thread function void terminate(); // Force exit thread function void quit(); // Thread exit function ...// Omit Q_SIGNALS: void started(QPrivateSignal); // Thread start signal void finished(QPrivateSignal); // Thread end signal protected: virtual void run(); int exec(); ...// Omit }; #else // QT_NO_THREAD ``` From the above two versions of the code, you can see that , These functions have little difference in declaration , But look carefully , Two versions of **run()** Does the function declare something different ? * Qt4.0.1 edition **run()** Functions are pure virtual functions , That is, this class is an abstract class and cannot create an instance item , Only indicators that point to this class can be created , That is, if you need to use QThread To implement multithreading , It has to be realized QThread And implement **run()** Function ; * Qt5.6.2 Version of **run()** Functions are virtual functions , Inherit QThread Class time , It can be realized again **run()** Function , It can't be realized . ** notes : I looked at several Qt The original code of the version , The version with the above difference was found from Qt4.4 Starting . From Qt4.4 The version begins ,QThread Classes are no longer abstract classes .** # QThread::start() Source code Let's take a look at QThread::start() Source code ,Qt4.0.1 Version and Qt5.6.2 The source code of this part of the version is similar , So Qt5.6.2 The source code of the version is mainly , as follows : ```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; ... ... // This part is d Index allocation #ifndef Q_OS_WINRT ... ... // This part is a note 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
(&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) { ... ... // This section configures thread prioritization 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"); } } ``` Pick out the key points to illustrate : **(1)Q_D() Macro definition ** When looking at the source code , At that time, I was more curious start The first statement of a function **Q_D() Macro definition ** What does it mean , So I looked at the source code , By the way ,**Q_D()** The source code is a ** Macro definition **, as follows : ```cpp #define Q_D(Class) Class##Private * const d = d_func() ``` Here we make use of the preprocessing macro ## The operator : Two symbols before and after the connection , Become a new symbol . Will Q_D(QThread) After unfolding , Become :QThreadPrivate * const d = d_func(). **(2)_beginthreadex() Function ** above d->handle = (Qt::HANDLE) _beginthreadex ( NULL, d->stackSize, QThreadPrivate::start, this, CREATE_SUSPENDED, &( d->id ) ) A function in a statement is a function that creates a thread , Its prototype and the explanation of each argument are as follows : ```cpp unsigned long _beginthreadex( void *security, // Security properties ,NULL For default security properties unsigned stack_size, // Specifies the size of the thread stack . If it is 0, The thread stack size is the same as the thread that created it . It's usually used 0 unsigned ( __stdcall *start_address )( void * ), // Specifies the address of the thread function , This is the address of the function that the thread calls to execute ( Use the function name , The function name means the address ) void *arglist, // An indicator of the arguments passed to the thread , You can pass in the index of the object , The index of the corresponding class in the function of the line // If you pass in this, This this It means a call QThread::start Object address of , That is to say QThread Or its derived class object itself unsigned initflag, // Thread initial state ,0: Execute immediately ;CREATE_SUSPEND:suspended( Hang up ) unsigned *thrdaddr // Used to record threads ID The address of ); ``` # QThreadPrivate::start() Source code From QThread::start() The source code can tell ,QThreadPrivate::start It's the point , It's actually a call QThreadPrivate::start(this), This **this** It means a call QThread::start Object address of , That is to say QThread Or its derived class object itself . Because of two Qt The source code of this part of the version is similar , So this part is mainly to 5.6.2 The source code of the version is mainly , Its original code and description are as follows : ```cpp // Arguments arg That's what I said above this unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg) { QThread *thr = reinterpret_cast
(arg); QThreadData *data = QThreadData::get2(thr); // Create thread culture storage variables , Storing threads id qt_create_tls(); TlsSetValue(qt_current_thread_data_tls_index, data); data->threadId = reinterpret_cast
(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); ...// Omit emit thr->started(QThread::QPrivateSignal()); // Send thread start signal QThread::setTerminationEnabled(true); thr->run(); // call QThread::run() Function -- Thread functions finish(arg); // End thread return 0; } ``` It can be seen from the above source code that , Actually **run()** The function is called here , And sent out **started()** Start signal , wait until **run()** Function execution finished , Finally, there was a call **QThreadPrivate::finish** Function ends the thread , And in finish It will send out **QThread::finished()** The signal that the thread has ended . # QThread::run() Source code I want to see others QThread::run() The original code of the function . on top 《2.1 QThread Class definition source code 》 The small section of , We can see two Qt Versions declare this method differently ,Qt-4.0 Version defines this as a pure virtual function , and Qt-5.6 Version defines this as a virtual function , Let's see Qt-5.6 In the version ,QThread::run() How to define , as follows : ```cpp void QThread::run() { (void) exec(); } ``` 1. Every one of them Qt The application has at least one ** The events go back and forth ** , It's a call **QCoreApplication::exec()** The event of the circle . But ,QThread It can also open the event loop . It's just that this is an event loop that is limited to the thread itself . So we're going to call main() The thread of the function , And by **QCoreApplication::exec()** Create the open event loop to be ** Main event loop ** , Or just call it ** The main loop ** . Be careful ,QCoreApplication::exec() You can only call main() The thread call of a function . The thread of the main loop is the main thread , Also known as GUI Thread , Because it's all about GUI All operations must be performed in this thread .QThread The regional event loop can be done through the **QThread::run()** Call me **QThread::exec()** Turn on . 2. We can see from the above source code , Its definition is simple , It's a call to a function :**QThread::exec()** Open thread ** The events go back and forth ** , We can also inherit QThread, Rewrite run() The way a function works , Let it implement relatively complex logic code . If your thread needs to complete some slot functions in this thread , You have to open the event loop , Otherwise, we can't respond to all kinds of signals and act accordingly . ** Summary :** Than Qt-4.4 In earlier versions , We use QThread When starting a thread , We must inherit from QThread Derived classes of , And be sure to rewrite run Function , If you need to use event loops , It needs to be in run Add... To the function exec(). here we are Qt4.4 After the version ( Include Qt4.4 edition ),QThread It's not an abstract class , You can instantiate without deriving , Without rewriting QThread::run() Method ,start The startup thread is the default start event loop . ** notes : When the program runs exec() Code , Located in exec() The later code will no longer be executed , Unless we use quit、exit Wait for the exit statement to exit the event loop , After quitting , The program will continue to run at exec() The code behind it .** # QThread::quit()、QThread::exit()、QThread::terminate() Source code The difference between thread stop functions , From Qt Source code to analyze : **(1)QThread::quit()、QThread::exit()** ```cpp //QThread::quit() Declare void quit(); //QThread::quit() Define void QThread::quit() { exit(); } //QThread::exit() Declare void exit(int retcode = 0); //QThread::exit() Define void QThread::exit(int returnCode) { Q_D(QThread); QMutexLocker locker(&d->mutex); d->exited = true; d->returnCode = returnCode; d->data->quitNow = true; for (int i = 0; i < d->data->eventLoops.size(); ++i) { QEventLoop *eventLoop = d->data->eventLoops.at(i); eventLoop->exit(returnCode); } } ``` From the above source code we can see ,**QThread::quit()** and **QThread::exit(0)** Is equivalent to , It's a loop of events that tells the thread , With return code 0( success ) sign out . If the thread has no events , Then this function does nothing , That is, invalid . When the thread has an event loop and is in ** The events go back and forth (QThread::exec())** In the state of , call **QThread::quit() perhaps QThread::exit()** The thread stops immediately , Otherwise, the thread will not stop immediately , Until the thread is in an event loop, that is, executing **QThread::exec()** When , To stop the thread . If you repeat the call **QThread::quit() perhaps QThread::exit()** Will it have any impact ? Repeat call **QThread::quit() perhaps QThread::exit()** It won't make any difference , Because only threads with event loops , These two functions will take effect to stop the thread function . **(2)QThread::terminate()** ```cpp void QThread::terminate() { Q_D(QThread); QMutexLocker locker(&d->mutex); if (!d->running) return; if (!d->terminationEnabled) { d->terminatePending = true; return; } // Calling ExitThread() in setTerminationEnabled is all we can do on WinRT #ifndef Q_OS_WINRT TerminateThread(d->handle, 0); #endif QThreadPrivate::finish(this, false); // End thread function } ``` In the last statement of this function definition , It's a call **QThreadPrivate::finish(this, false);** Function , Its function is to exit the thread directly , Whether the thread turns on the event loop or not, the loop will take effect , Will immediately terminate a thread , But this function has a very unstable factor ,** It is not recommended to use **. If you repeat the call **QThread::terminate()** Will it have any impact ? No effect . We can see the third sentence in the function body , It first determines whether the thread is still running , If not , Will exit the function directly , You don't go on with the call **QThreadPrivate::finish(this, false);** Function . # Chapter summary I believe I have seen some of the above QThread Source code , I know about it QThread The nature of classes and QThread The process from opening to ending . Here I'll briefly summarize : **(1)QThread The essence of :** * QThread It's used to manage threads , The thread it depends on is not the same as the thread it manages ; * QThread The thread is attached to , It's execution QThread t or QThread * t=new QThread Where the thread is ; * QThread Management threads , Namely run Started thread , It's a thread . **(2) Here's to Qt4.4 After the version ( Include Qt4.4 edition ) A brief summary of the thread start to end process :** * QThread Objects or QThread Derived class objects explicitly call QThread Outside of a class start() Method ; * QThread::start() Method call again QThreadPrivate::start() Method ; * stay QThreadPrivate::start() Call in method QThread::run() Virtual functions , For users, it's only here that they really enter a new thread . That is to say, to define QThread Objects or QThread When deriving class objects , Still in the original thread , Only by entering run The function is entering a new thread ; * stay QThreadPrivate::start() Method calls QThread::run() After the virtual function ends , It's going to keep calling QThreadPrivate::finish() Function to end the thread , And signal the end of the thread finished(). **(3)QThread::quit()、QThread::exit()、QThread::terminate():** * Reuse these three stop thread functions for threads , There's no effect ; * Try not to use QThread::terminate() Stop the thread , This way is to force the thread to exit , There's no security . * call QThread::quit() and QThread::exit() The same thing . **(4)Qt Various versions QThread Class changes :** * Qt4.4 Before the release QThread Class is an abstract class , Qt4.4 After the version ( Include 4.4 edition ) It's not smoking
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢