当前位置:网站首页>Analysis of the original code of [QT] qthread

Analysis of the original code of [QT] qthread

2020-11-07 16:50:03 itread01

It will be singled out in this chapter 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 . # One 、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 .** # Two 、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 ); ``` # 3、 ... and 、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 . # Four 、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 .** # 5、 ... and 、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 . # 6、 ... and 、 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]所创,转载请带上原文链接,感谢