Android framework Thread(native层)

源码位置

android-12.0.0_r28/system/core/libutils/include/utils/Thread.h

android-12.0.0_r28/system/core/libutils/Threads.cpp

android-12.0.0_r28/system/core/libutils/include/utils/Mutex.h

android-12.0.0_r28/system/core/libutils/include/utils/Condition.h

android-12.0.0_r28/system/core/libutils/include/utils/RefBase.h

(RefBase是用于记录对象被引用的次数,可参考我这篇进行学习:Android framework RefBase,sp,wp)

简述

Thread类其实就是封装了 POSIX 线程库(pthread)(可参考我这篇进行学习:Linux的POSIX线程),提供的基础功能涵盖了线程的生命周期:创建、运行、销毁。

成员函数

私有方法:

virtual bool threadLoop() = 0:

这是一个虚函数,派生类必须实现threadLoop()。线程从这里开始它的生命。有两种使用Thread对象的方式:

  • 循环执行:如果threadLoop()返回 true,如果requestExit()没有被调用,它将再次被调用。

  • 执行一次:如果threadLoop()返回 false,线程将在返回时退出。

公有方法:

virtual status_t run(const char* name, int32_t priority = PRIORITY_DEFAULT,size_t stack = 0)

启动线程时,需要调用该方法run

virtual void requestExit()

让这个对象的线程退出。这个函数是异步的,当函数返回时,线程可能仍然在运行。当然,这个函数可以从不同的线程调用。

virtual status_t readyToRun()

在开始循环执行或者执行一次threadLoop()之前会调用该方法readyToRun(),可在线程运行前执行一次初始化或者不耗时的操作。

status_t requestExitAndWait()

调用requestExit()并等待,直到该对象的线程退出,这种情况下,会阻塞线程,所以要特别注意死锁。

status_t join()

等待这个对象的线程退出。如果尚未运行,则立即返回。如果仍在运行,则会阻塞线程,直到等待线程执行完后返回

bool isRunning() const

表示此线程是否正在运行。

实例

MyThread.cpp

#include <utils/Thread.h>
#include <utils/RefBase.h>
#include <stdio.h>
using namespace android;
class MyThread : public Thread {
    
    
private:
	int count = 0;
public:
    MyThread() {
    
     printf("MyThread created\n"); }
    bool threadLoop() {
    
    
		printf("threadLoop count = %d\n",count);
		count--;
		if (count == 0) {
    
    
			return false;		
		}
		return true;
	}
	status_t readyToRun(){
    
    
		count = 10;
		printf("readyToRun init the count = %d\n",count);
		return OK;
	}
};

int main(){
    
    
	sp<MyThread> myThread = new MyThread();
	myThread->run("MyThread"); //看源码分析
	printf("error=%s", strerror(errno));
	return 0;
}
/*
执行结果
MyThread ---created
readyToRun init the count = 10
threadLoop count = 10
threadLoop count = 9
threadLoop count = 8
threadLoop count = 7
threadLoop count = 6
threadLoop count = 5
threadLoop count = 4
threadLoop count = 3
threadLoop count = 2
threadLoop count = 1
*/

MyThread.cpp放到Android源码编译(我的是android-12.0.0_r28),然后编写它的Android.bp

cc_binary {
    name: "MyThread",
    srcs: ["MyThread.cpp"],
    shared_libs: ["libutils"],
    cflags: [
        "-Wno-unused-variable",
        "-Wno-unused-parameter",
    ],
}

将生成的二进制文件MyThread(一般在out/target/product/xxxx/system/bin/MyThread),push进设备的/system/bin/目录,

再进入设备的shell环境,执行./system/bin/MyThread

adb push \xxx\out\target\product\xxx\system\bin\MyThread /system/bin
adb shell
xxxxx:/ # ./system/bin/MyThread

源码分析

android-12.0.0_r28/system/core/libutils/Threads.cpp

Thread

启动线程时,我们会主动调用run方法,看看run方法做了哪些操作,

status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    
    
    LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to Thread::run");
	//获取自动锁,当变量_l被释放了,就会自动解锁。看Mutex分析
    Mutex::Autolock _l(mLock);
	//如果线程在运行,则返回非法操作
    if (mRunning) {
    
    
        // thread already started
        return INVALID_OPERATION;
    }
    //...省略一堆代码
    //判断是否在退出
    mExitPending = false;
	//...省略一堆代码
    bool res;
    //从Thread 默认的构造方法看,mCanCallJava的值默认为true,
    if (mCanCallJava) {
    
    
        //1.1、最终会调用到Threap中的androidCreateRawThreadEtc
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    } else {
    
    
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
    ...
    return OK;
}

int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                               void *userData,
                               const char* threadName __android_unused,
                               int32_t threadPriority,
                               size_t threadStackSize,
                               android_thread_id_t *threadId)
{
    
    
    //...省略一堆代码
    
    //1.2、所以android native 层的Thread,其实是用了POSIX线程中的pthread_create方法创建的,
    //而线程执行体就是_threadLoop()方法
    int result = pthread_create(&thread, &attr,
                    (android_pthread_entry)entryFunction, userData);
    //...省略一堆代码  
}

int Thread::_threadLoop(void* user)
{
    
    
    // 派生派(即上面实例的MyThread类)
    Thread* const self = static_cast<Thread*>(user);

    //...省略一堆代码

    bool first = true;

    do {
    
    
        bool result;
        //进入do while 循环
        if (first) {
    
    
            first = false;
            //1.3、通过first变量,从true到false,来判断第一次进入时调用readyToRun()
            self->mStatus = self->readyToRun();
            result = (self->mStatus == OK);
			//readyToRun是OK的并且线程是没有退出动作时,
            //就会调用成员函数threadLoop(),即会调会子类的threadLoop(),
            if (result && !self->exitPending()) {
    
    
                // Binder threads (and maybe others) rely on threadLoop
                // running at least once after a successful ::readyToRun()
                // (unless, of course, the thread has already been asked to exit
                // at that point).
                // This is because threads are essentially used like this:
                //   (new ThreadSubclass())->run();
                // The caller therefore does not retain a strong reference to
                // the thread and the thread would simply disappear after the
                // successful ::readyToRun() call instead of entering the
                // threadLoop at least once.
                result = self->threadLoop();
            }
        } else {
    
    
            //
            result = self->threadLoop();
        }

        // establish a scope for mLock
        {
    
    
        Mutex::Autolock _l(self->mLock);
        //1.4根据派生类重写threadLoop()的返回值,判断继续循环或者只执行一次,
        //并把设置相关状态mExitPending和mRunning  
        if (result == false || self->mExitPending) {
    
    
            self->mExitPending = true;
            self->mRunning = false;
            //...省略一堆代码
            //当调用requestExitAndWait时,如果线程还在运行,就会阻塞,
            //当线程完成后,就会通过条件变量mThreadExitedCondition.broadcast()唤醒在等待中的线程。
			//看Condition分析
            self->mThreadExitedCondition.broadcast();
            break;
        }
        }
		//...省略一堆代码
    } while(strong != nullptr);//1.5 继续下一轮的循环

    return 0;
}

所以,Thread类其实就是封装了Linux的POSIX线程创建和销毁等相关方法

Mutex

android-12.0.0_r28/system/core/libutils/include/utils/Mutex.h

//...省略一堆代码
inline Mutex::Mutex() {
    
    
    //调用POSIX的初始化互斥锁
    pthread_mutex_init(&mMutex, nullptr);
}

//...省略一堆代码
inline status_t Mutex::lock() {
    
    
    //调用POSIX的获取互斥锁
    return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
    
    
    //调用POSIX的释放互斥锁
    pthread_mutex_unlock(&mMutex);
}
//...省略一堆代码
class SCOPED_CAPABILITY Autolock {
    
     //SCOPED_CAPABILITY是宏定义
      public:
    	//在构造和析造函数里分别获取锁和释放锁,即某变量在某代码段被回收了,就会调用析造函数从而自动解锁。防止死锁或者自己忘记解锁操作。
        inline explicit Autolock(Mutex& mutex) ACQUIRE(mutex) : mLock(mutex) {
    
     mLock.lock(); }
        inline explicit Autolock(Mutex* mutex) ACQUIRE(mutex) : mLock(*mutex) {
    
     mLock.lock(); }
        inline ~Autolock() RELEASE() {
    
     mLock.unlock(); }

      private:
        Mutex& mLock;
        // Cannot be copied or moved - declarations only
        Autolock(const Autolock&);
        Autolock& operator=(const Autolock&);
    };
// 所以Autolock在自己的生命周期内,自动加锁也会自动放锁的类
typedef Mutex::Autolock AutoMutex;
//...省略一堆代码

Mutex类其实就是封装了Linux的POSIX线程互斥锁等相关方法**

Condition

android-12.0.0_r28/system/core/libutils/include/utils/Condition.h

//...省略一堆代码
inline status_t Condition::wait(Mutex& mutex) {
    
    
    //调用POSIX的条件变量:等待某个条件变量的线程广播一个信号
    return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
//...省略一堆代码
inline void Condition::signal() {
    
    
    //调用POSIX的条件变量:向等待某个条件变量的线程广播一个信号,唤醒一个等待在条件变量上的线程
    pthread_cond_signal(&mCond);
}
 
inline void Condition::broadcast() {
    
    
    //调用POSIX的条件变量:向等待某个条件变量的线程广播一个信号,以唤醒所有等待该条件变量的线程
    pthread_cond_broadcast(&mCond);
}
//...省略一堆代码

Condition类其实就是封装了Linux的POSIX线程条件变量等相关方法

工作原理与总结

  1. 创建派生类XXX继承Thread,重写threadLoop()方法,执行所需要的代码.

  2. 创建xxx类对象,并启动运行(通过run方法),此时Thread内部会在_threadLoop()调用:

    2.1. 只执行一次readyToRun()

    2.2. 循环执行步骤1中派生类重写的 threadLoop()注意:重写的threadLoop()返回值确定是否继续循环执行的方法。

  3. 请求退出方法,可调用requestExit()函数或者requestExitAndWait函数

猜你喜欢

转载自blog.csdn.net/weixin_45767368/article/details/129286765