Android开发之Thread类分析
转自: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()方法,启动函数
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。