Android thread class & threadloop
背景
本週在除錯過程中,發現了一個神奇的執行緒函式threadLoop,找遍模組內部所有的程式碼,居然沒有找到該函式是在何處拉起的,僅僅知道這是個迴圈執行緒,但想要解決問題,必須知道執行緒是何時被拉起的,帶著這樣的疑問我開始了對threadloop的調查。
簡述
threadloop顧名思義是一個迴圈執行緒,只要返回值為true,則執行緒就會反覆執行,而該方法的呼叫關係就藏在thread class裡面。對於thread class這個類,我的個人理解是將執行緒建立跟管理的部分抽象出來,既是方便管理,也是在提高程式碼的複用率。而使用者在自己的派生類中繼承thread class,並實現父類中的虛擬函式(threadloop就是其中一個),即可實現對執行緒的管理,下面我們舉例項說明thread class的大致呼叫關係及應用方法。
thread class成員
註釋太長不貼了,原始碼位置:/system/core/libutils/include/utils/Thread.h
class Thread : virtual public RefBase
{
public:
explicit Thread(bool canCallJava = true);
virtual ~Thread();
virtual status_t run( const char* name,
int32_t priority = PRIORITY_DEFAULT,
size_t stack = 0);
virtual void requestExit();
virtual status_t readyToRun();
status_t requestExitAndWait();
status_t join();
bool isRunning() const;
#if defined(__ANDROID__)
pid_t getTid() const;
#endif
protected:
bool exitPending() const;
private:
virtual bool threadLoop() = 0;
private:
Thread& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
thread_id_t mThread;
mutable Mutex mLock;
Condition mThreadExitedCondition;
status_t mStatus;
volatile bool mExitPending;
volatile bool mRunning;
sp<Thread> mHoldSelf;
#if defined(__ANDROID__)
pid_t mTid;
#endif
};
應用例項
我們以Android中bootanimation為例,原始碼位置:/frameworks/base/cmds/bootanimation/
1.在標頭檔案中我們可以看到繼承關係
class BootAnimation : public Thread, public IBinder::DeathRecipient
2.在onFirestRef函式中,呼叫了run()方法,有關函式onFirstRef()的呼叫關係可查閱資料,此處不做過多描述
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
run("BootAnimation", PRIORITY_DISPLAY);
}
}
3.run()方法的實現在父類thread class中,程式碼路徑:/system/core/libutils/Threads.cpp
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
...
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
...
return NO_ERROR;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
擷取其中建立執行緒的關鍵程式碼,最終呼叫androidCreateRawThreadEtc()
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName __android_unused,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId)
{
...
pthread_t thread;
int result = pthread_create(&thread, &attr,
(android_pthread_entry)entryFunction, userData);
pthread_attr_destroy(&attr);
if (result != 0) {
ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
"(android threadPriority=%d)",
entryFunction, result, strerror(errno), threadPriority);
return 0;
}
...
return 1;
}
在這段程式碼中我們看到了非常熟知的函式pthread_create(),而執行緒函式是在上一段程式碼中的_threadLoop()
4._threadLoop()執行緒被建立後,來到了非常核心的部分
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast<Thread*>(user);
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
#if defined(__ANDROID__)
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
// running at least once after a successful ::readyToRun()
// (unless, of course, the thread has already been asked to exit
// at that point).
// This is because threads are essentially used like this:
// (new ThreadSubclass())->run();
// The caller therefore does not retain a strong reference to
// the thread and the thread would simply disappear after the
// successful ::readyToRun() call instead of entering the
// threadLoop at least once.
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
// establish a scope for mLock
{
Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mRunning = false;
// clear thread ID so that requestExitAndWait() does not exit if
// called by a new thread using the same thread ID as this one.
self->mThread = thread_id_t(-1);
// note that interested observers blocked in requestExitAndWait are
// awoken by broadcast, but blocked on mLock until break exits scope
self->mThreadExitedCondition.broadcast();
break;
}
}
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
strong.clear();
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
} while(strong != 0);
return 0;
}
1.我們看到了while迴圈,這是threadloop能夠被反覆呼叫的原因;
2.flag first,意義在於進入迴圈第一次後會呼叫方法readyToRun(),這個是父類thread class虛擬函式,需要子類實現,一般用於初始化動作,為後續迴圈執行緒做準備;
3.readyToRun()方法呼叫返回後,如返回值無誤,則直接呼叫threadLoop(),跟readyToRun()一樣,是父類thread class虛擬函式,同樣需要子類實現,這也是我最終想要搞清楚的地方;
4.first過後,再次進入迴圈時走else分支,直接呼叫threadLoop(),如返回值為false,則break迴圈執行緒退出。
補充說明
至此threadloop呼叫關係已完全透明,迴圈執行緒的應用場景一般是用來處理佇列訊息,需要一直迴圈監聽,執行緒內部配合一個阻塞的監聽函式,有訊息上來就從監聽函式返回,處理一下帶出來的資料,處理完畢進入下一個迴圈。
參考連結:https://blog.csdn.net/ch853199769/article/details/79917188
相關文章
- ThreadLoop實踐學習筆記threadOOP筆記
- Android APIs (Class Index - Android SDK)(一)AndroidAPIIndex
- Android APIs (Class Index - Android SDK)(二)AndroidAPIIndex
- Android:Unable to find explicit activity classAndroid
- 十六、Android效能優化之threadAndroid優化thread
- Android中的Handler, Looper, MessageQueue和ThreadAndroidOOPthread
- 轉android-Service和Thread的區別Androidthread
- Android執行緒管理之Thread使用總結Android執行緒thread
- Android開發實踐:使用Service還是ThreadAndroidthread
- Android中Handler Runnable與Thread的區別詳解Androidthread
- Threadthread
- Android/java 多執行緒(二)-Thread的好兄弟HandlAndroidJava執行緒thread
- iOS[super class]和[self class]iOS
- Error:Could not determine the class-path for interface com.android.builder.modelErrorAndroidUI
- JNI開發:Class android.content.Context could not be foundAndroidContext
- Typescript的interface、class和abstract classTypeScript
- Hello,Threadthread
- Thread類thread
- Thread jointhread
- self::class和static::class的區別
- Didn't find class "android.support.v7.widget.RecyclerView"AndroidView
- Android中使用Thread造成記憶體洩露的分析和解決Androidthread記憶體洩露
- Thread.jointhread
- Thread知識thread
- redolog threadthread
- Thread(C#)threadC#
- 記一次 報錯:Android ClassNotFoundException: Didn't find class on pathAndroidException
- tomcat one connection one thread one request one threadTomcatthread
- Android學習開發(問題解決)——android Unable to inflate view tag without class attributeAndroidView
- Android/java 多執行緒(一)-Thread的使用以及原始碼分析AndroidJava執行緒thread原始碼
- dart class overviewDartView
- JavaScript class 類JavaScript
- this與class(原型)原型
- JavaScript:類(class)JavaScript
- Class詳解
- case class inheritance
- Type與Class
- [Javascript] Class & PrototypesJavaScript