標籤:android style blog http color io 使用 ar java
轉自:http://blog.csdn.net/llping2011/article/details/9706599
在我們Linux系統中建立線程函數為:pthread_create(),在Android中我們為線程封裝了一個類Thread,實際調用的還是pthread_create()
當我們想建立線程的時候,只需要繼承於這個Thread類並實現虛函數thread_loop()即可。
frameworks/base/include/utils/threads.h class Thread : virtual public RefBase { public: // 建立一個Thread對象,但是並不立即啟動線程函數 Thread(bool canCallJava = true); virtual ~Thread(); // 開始啟動線程函數,調用的是threadLoop virtual status_t run(const char*name = 0, int32_t prority = PRIORITY_DEFAULT, size_t stack = 0); // 申請退出這個線程 virtual void requestExit(); virtual status_t readyToRun(); // 調用requestExit()等待直到這個線程退出 status_t requestExitAndWait(); // 等待直到線程退出,如果沒有啟動立即返回 status_t join(); protected: // 如果調用了requestExit()返回true bool exitPending() const; private: // 這是實際的線程函數,繼承類必須實現它, // 返回true的話再次調用,返回false的話就會退出 virtual bool threadLoop() = 0; // 禁止賦值 Thread& operator = (const Thread&); // 內部類,被run函數調用,實際調用threadLoop static int _threadLoop(void* user); const bool mCanCallJava; thread_id_t mThread; // thread_id_t 其實是 void*類型 mutable Mutex mLock; Condition mThreadExitedCondition; status_t mStatus; // 注意:所以操作這兩個變數的地方都需要上鎖 volatile bool mExitPending; volatile bool mRunning; sp<Thread> mHoldSelf; };
我們首先看下Thread類的建構函式:
Thread::Thread(bool canCallJava) : mCanCallJava(canCallJava), mThread(thread_id_t(-1)), mLock("Thrad::mLock"), mStatus(NO_ERROR), mExitPending(false), mRunnig(false) {}
真正啟動線程的函數:
status_t Thread::run(const char*name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock); if(mRunnig) return INVALID_OPERATION; mState = NO_ERROR; mExitPending = false; mThread = thread_id_t(-1); mHoldSelf = this; // 儲存著當前對象的引用 mRunning = true; if (mCanCallJava) res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); else res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); if(res == false) { mStatus = UNKNOWN_ERROR; mRunning = false; mThread = thread_id_t(-1); mHoldSelf.clear(); return UNKNOWN_ERROR; } return NO_ERROR; } 這裡有個判斷mCanCallJava是個什麼東西?接著往下看 inline bool createThreadEtc(thread_func_t entryFunction, void* userData, const char* threadName = "android:unnamed_thread", int32_t threadPriority = PRIORITY_DEFAULT, size_t threadStackSize = 0, thread_id_t *threadId = 0) { return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId) ? true : false; } int androidCreateThreadEtc(thread_func_t entryFunction, void* userData, const char* threadName, int32_t threadPriority = PRIORITY_DEFAULT, size_t threadStackSize = 0, thread_id_t *threadId = 0) { return gCreateThreadFn(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId); }
我們看到最後調用的是gCreateThreadFn這個函數,而gCreateThreadFn是個全域的函數指標,
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
這裡預設給它賦值為 androidCreateRawThreadEtc,這跟前面調用的是一樣的???
既然是函數指標肯定有給它賦值的地方:
void androidSetCreateThreadFunc(android_create_thread_fn func) { gCreateThreadFn = func; }
那這個函數在什麼地方調用的呢?又給它賦什麼值了呢?
我們找到了再AndroidRuntime類裡面啟動虛擬機器的地方:
int androidRuntime::startReg(JNIEnv* env) { androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); return 0; }
這樣如果我們的mCanCallJava如果為true的話,調用的就是:
int AndroidRuntime::javaCreateThreadEtc(android_thread_func_t entryFunction, void* userData, const char* threadName, int32_t threadPriority, suze_t threadStackSize, android_thread_id_t *threadId) { void** args = (void**)malloc(3*sizeof(void*)); args[0] = (void*)entryFunction; args[1] = userData; args[2] = (void*)strdup(threadName); return androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args. threadName, threadPriority, threadStackSize, threadId); }
最後調用的還是同一個建立線程的函數只是回呼函數不一樣,這裡變成了AndroidRuntime::javaThreadShell
int AndroidRuntime::javaCreateThreadEtc(void* args) { voir* start = ((void**)args)[0]; voir* userData = ((void**)args)[1]; voir* name = ((void**)args)[2]; free(args); JNIEnv* env; javaAttachThread(name, &env); result = (*(android_thead_func_t)start)(userData); javaDetachThread(); free(name); return result; }
這裡線程函數javaThreadShell裡面還是調用前面我們的_threadLoop函數,只不過在調用之前,調用
了javaAttachThread()將線程attach到JNI環境中去了,這樣線程函數就可以調用JNI函數,最後線程
函數退出之後再調用javaDetachThread()退出JNI環境。
現在進入線程函數_threadLoop(),這是一個static函數
int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); sp<Thead> strong(self->mHoldSelf); wp<Thead> weak(strong); self->mHoldSelf.clear(); bool first = true; do { // 進入一個迴圈,通過判斷傳回值和內部退出標誌位決定是否退出線程 bool result; if (fisr) { first = false; self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); if (result && !self->exitPendind()) { // 檢查是否退出 result = self->threadLoop(); // 調用實際線程函數 } } else { result = self->threadLoop(); } { Mutex::Autolock _l(self->mLock); if (result == false || self->mExitPending) { self->mExitPending = true; self-mRunning = false; self->mThread = thread_ir_t(-1); self->mThreadExitedCondition.broadcast(); break; } } strong.clear(); strong = weak.promote(); } while(strong != 0); return 0; }
在這裡線程退出的條件為:
1)result = true 意味著子類在實現的threadLoop函數中返回false,這樣線程就主動退出了
2)mExidPendding = true 這個變數值由Thread類的requestExit函數設定,這樣線程就被動退出了。
最後如果線程退出了需要進行些去初始化操作,設定線程運行狀態,廣播告知其他關心這個線程的對象。
最後,如果我們想使用線程類: 1)建立一個類如MyThread,繼承與Thead類 2)在MyThread類中實現父類的純虛函數threadLoop,也就是我們調用pthread_create時傳入的線程函數。 3)定義一個MyThread變數 thread,調用線程的run()方法,啟動函數
Android開發之Thread類分析 (轉載)