一.初步认识
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
};
上面类定义中看到很多内容,其实真正创建线程的地方是在run方法中,我们来看一下它的run函数。
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方法要写好。还是看代码吧。