Thread 类其实就是对Linux api做的一个封装,它的代码是在/sysem/core/libutils/thread.cpp。在Android service和camera 流处理中我们都会发现它的影子。就我个人来说,在没看研究thread类时,虽然我知道它是一个线程类,但是用起来还是心里发虚。
例如在Camera service中,各种帧流都会开一个线程来处理,代码在framework/av/services/camera/libcameraservice/api1/camera2client.cpp initialize方法中。
mStreamingProcessor = new StreamingProcessor(this); threadName = String8::format("C2-%d-StreamProc", mCameraId); mStreamingProcessor->run(threadName.string()); //preview,video流处理线程 mFrameProcessor = new FrameProcessor(mDevice, this); threadName = String8::format("C2-%d-FrameProc", mCameraId); mFrameProcessor->run(threadName.string()); mCaptureSequencer = new CaptureSequencer(this); threadName = String8::format("C2-%d-CaptureSeq", mCameraId); mCaptureSequencer->run(threadName.string()); //拍照处理线程
Android源码中Thread类的定义如下,其实google已经写了很多注释了,大家还是看看原汁原味吧。
class Thread : virtual public RefBase { public: // Create a Thread object, but doesn't create or start the associated // thread. See the run() method. Thread(bool canCallJava = true); //canCalljava表示这个函数是否使用JNI函数,这里可以看到它默认为true,请继续看下面的代码创建。 virtual ~Thread(); // Start the thread in threadLoop() which needs to be implemented. virtual status_t run( const char* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0); // Ask this object's thread to exit. This function is asynchronous, when the // function returns the thread might still be running. Of course, this // function can be called from a different thread. virtual void requestExit(); // Good place to do one-time initializations virtual status_t readyToRun(); // Call requestExit() and wait until this object's thread exits. // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call // this function from this object's thread. Will return WOULD_BLOCK in // that case. status_t requestExitAndWait(); // Wait until this object's thread exits. Returns immediately if not yet running. // Do not call from this object's thread; will return WOULD_BLOCK in that case. status_t join(); // Indicates whether this thread is running or not. bool isRunning() const; #ifdef HAVE_ANDROID_OS // Return the thread's kernel ID, same as the thread itself calling gettid() or // androidGetTid(), or -1 if the thread is not running. pid_t getTid() const; #endif protected: // exitPending() returns true if requestExit() has been called. bool exitPending() const; private: // Derived class must implement threadLoop(). The thread starts its life // here. There are two ways of using the Thread object: // 1) loop: if threadLoop() returns true, it will be called again if // requestExit() wasn't called. // 2) once: if threadLoop() returns false, the thread will exit upon return. virtual bool threadLoop() = 0; private: Thread& operator=(const Thread&); static int _threadLoop(void* user); const bool mCanCallJava; // always hold mLock when reading or writing thread_id_t mThread; mutable Mutex mLock; Condition mThreadExitedCondition; status_t mStatus; // note that all accesses of mExitPending and mRunning need to hold mLock volatile bool mExitPending; volatile bool mRunning; sp<Thread> mHoldSelf; #ifdef HAVE_ANDROID_OS // legacy for debugging, not used by getTid() as it is set by the child thread // and so is not initialized until the child reaches that point pid_t mTid; #endif };
status_t Thread::run(const char* name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock); ........ // reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = NO_ERROR; mExitPending = false; mThread = thread_id_t(-1); // hold a strong reference on ourself mHoldSelf = this; mRunning = true; //线程运行标志位为true,表示线程运行起来了。 bool res; if (mCanCallJava) { //之前从Thread类中发现这个值为真 res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } .......... }上面由类声明中我们知道mCanCallJava为真,我们可以发现if else中传入的参数都是一样的,我们来跟一下createThreadEtc代码。代码:system/core/include/utils/AndroidThreads.h
// Create thread with lots of parameters 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; }上面我们看到,它又调用了androidCreateThreadEtc,我们继续来跟一下。
int androidCreateThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId) { return gCreateThreadFn(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId); } void androidSetCreateThreadFunc(android_create_thread_fn func) { gCreateThreadFn = func; //这里是其它地方注册了一个回调函数。 }上面androidCreateThreadEtc又调用了一个函数指针,这个函数指针是通过androidSetCreateThreadFunc()注册下来的。我们来看看androidSetCreateThreadFunc()是在什么地方调用的。
在运行时刚开始的时候,就会调用startReg()注册这个回调。
/* * Register android native functions with the VM. */ /*static*/ int AndroidRuntime::startReg(JNIEnv* env) { /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ........ }
我们可以看到注册下去的是javaCreateThreadEtc()它的内容如下。
/* * This is invoked from androidCreateThreadEtc() via the callback * set with androidSetCreateThreadFunc(). * * We need to create the new thread in such a way that it gets hooked * into the VM before it really starts executing. */ /*static*/ int AndroidRuntime::javaCreateThreadEtc( android_thread_func_t entryFunction, //注意这里entryFunction = _threadLoop void* userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t* threadId) { void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free int result; if (!threadName) threadName = "unnamed thread"; args[0] = (void*) entryFunction; args[1] = userData; args[2] = (void*) strdup(threadName); // javaThreadShell must free result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, threadName, threadPriority, threadStackSize, threadId); return result; }上面可以看到又回到了androidCreateRawThreadEtc();我么可以发现它注册的function是AndroidRuntime::javaThreadShell(),其实在后续的处理还是会注册_threadLoop(),接口,而在_threadLoop()接口中又会循环调用用户自己定义的threadLoop().
/* * When starting a native thread that will be visible from the VM, we * bounce through this to get the right attach/detach action. * Note that this function calls free(args) */ /*static*/ int AndroidRuntime::javaThreadShell(void* args) { void* start = ((void**)args)[0]; void* userData = ((void **)args)[1]; //这个参数2是我们的thread_loop char* name = (char*) ((void **)args)[2]; // we own this storage free(args); JNIEnv* env; int result; /* hook us into the VM */ if (javaAttachThread(name, &env) != JNI_OK) return -1; /* start the thread running */ result = (*(android_thread_func_t)start)(userData); /* unhook us */ javaDetachThread(); free(name); return result; }
上面是android运行时的代码,后面我们分析android运行时的代码时,在分析这里代码。接下来我们来看一下,大家魂牵梦绕的loop函数。其实搞懂这个函数,我们大概也就知道thread类的运作机制了。
int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); //这里user就是继承了thread类的子类对象,其中实现了threadLoop方法。 sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); self->mHoldSelf.clear(); #ifdef HAVE_ANDROID_OS // 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(); //其实readyTorun直接返回的就是NO_ERROR. result = (self->mStatus == NO_ERROR); if (result && !self->exitPending()) { //第一次刚创建线程时走这个分支 //线程还没要退出,exitPending()得到就是0了。 result = self->threadLoop(); //运行用户自己的LOOP函数。 } } else { result = self->threadLoop(); //走到这里已经不是第一次进来了,如果线程没有意愿要退出,那就继续执行用户自己的LOOP函数。 } // establish a scope for mLock { Mutex::Autolock _l(self->mLock); if (result == false || self->mExitPending) { //到这来就是要退出了,在官方源码中注释有在操作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; }关于_thread_Loop,我们就介绍到这里,大家要认清,threadLoop运行在一个循环当中,它的创建是由run方法引发的,所以大家只要在调用的地方看到run方法,就说明创建线程了。而在很多情况下,我们看不到调用run方法的地方,其实如果你找不到run方法地方,可以去对象onFirstRef()方法中看看。
总结:大家在开发中,如果只是看代码了解架构的话,一开始不需要过多扣细节。大概知道怎么用的就行。像这里的Thread类,我们只需要知道调用了run方法,就创建了一个线程,此外一定要保证我们子类中的threadLopp方法要写好。还是看代码吧。