android底层库libutils之thread研究

一.初步认识

        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方法要写好。还是看代码吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值