在Android native(C++)层若想要创建一个线程则可以使用android平台native实现的Thread类来创建【当然你也可以直接使用C++标准库实现的std::thread,需引入头文件 #include,后续有时间再分析该标准库的实现】,而该类做了跨平台线程调用接口的处理和封装,具备了跨平台运行能力。
本系列文章分析的安卓源码版本:【Android 10.0 版本】
在此主要分析Android平台上的实现部分。
在native层使用该类必须引用android命名空间,因为该类是在android命名空间实现的,并引用该头文件【system/core/libutils/include/utils/Threads.h】,即可在自己的cpp文件中如下引用:
#include
Threads.h文件内容如下:
// [system/core/libutils/include/utils/Threads.h]
#ifndef _LIBS_UTILS_THREADS_H
#define _LIBS_UTILS_THREADS_H
/*
* Please, DO NOT USE!
*
* This file is here only for legacy reasons. Instead, include directly
* the headers you need below.
*
*/
#include
// __cplusplus (C++)该宏定义的作用是:告诉C++编译器将这下面包含的头文件中的方法实现,
// 都按照C编译器的方式来处理编译,然后才能用于和C代码库相互链接。
// 可参考这篇文章很详细的介绍:【#ifdef __cplusplus 有什么作用】
// https://blog.csdn.net/thanklife/article/details/7362893
#ifdef __cplusplus
#include
#include
#include
#include
#include
#endif
#endif // _LIBS_UTILS_THREADS_H
该头文件是一个线程功能集合体,提供了好几个头文件,其实若只是需要使用Thread线程类,我们不需要引用这么多头文件,因此正如文件中英文部分所指出的:
注意此处的英文注释的意思:意思就是最好不要再使用【threads.h】这个头文件,因为它是历史遗留原因造成的,相反,我们应该直接使用include下面所需的头文件即可,因此想用哪个头文件功能就直接引用它即可。
【另外主要区别就是:该threads.h头文件其实是用C编译器的方式编译代码的,因此在C++编程时不需要这么做】
因此可以更简单的头文件引入方式,如下:
只引入需要使用Thread线程类的头文件
#include
Thread类图:
Thread类声明:
声明的功能比较简单,类声明在android命名空间。
// [system/core/libutils/include/utils/Thread.h]
#ifndef _LIBS_UTILS_THREAD_H
#define _LIBS_UTILS_THREAD_H
#include
#include
#include
#if !defined(_WIN32)
# include
#endif
#include
#include
#include
#include
#include
#include
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
// 此处的英文表示,请不要使用该类,请使用std::thread类【C++标准库提供】来实现自己的线程,
// 应该是android自己实现的该类只提供给安卓native内部使用的吧。
// DO NOT USE: please use std::thread
// RefBase类是安卓智能指针的实现,此处不展开分析,可见后续相关分析章节
class Thread : virtual public RefBase
{
public:
// 显示调用构造函数
// explicit修饰符表示该类构造函数必须显示创建调用
// Create a Thread object, but doesn't create or start the associated
// thread. See the run() method.
explicit Thread(bool canCallJava = true);
virtual ~Thread();
// 启动线程运行
// 该方法可只传入线程名,其他两个参数为默认值
// priority:该参数表示当前线程的优先级别,主要用于CPU线程调用的处理
// 其取值范围常量定义在该头文件中
// stack:该参数表示线程大小
// Start the thread in threadLoop() which needs to be implemented.
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t run( const char* name,
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();
// 请求退出并等待退出完毕后该方法才返回(调用端),
// 即该方法会阻塞调用端线程,直到彻底退出后才返回。
// 警告:必须小心调用该方法,避免造成死锁,即千万别在当前线程中调用该方法,否则会返回错误状态(WOULD_BLOCK)
// 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();
// 等待线程(阻塞运行完毕),即该方法调用后会阻塞调用端线程,等待该线程执行完毕退出才返回调用端。
// 阻塞当前的(调用)线程,直到另外一个线程运行结束。
// 注意:若该线程未启动,则会立即返回。
// 警告:不要在该线程中调用该方法,否则会返回错误状态(WOULD_BLOCK)
// 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;
#if defined(__ANDROID__)
// 若存在安卓平台宏定义,则进入此处
// 返回该线程ID(线程内核ID)
// 注意:若该线程未启动则返回-1
// Return the thread's kernel ID, same as the thread itself calling gettid(),
// 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:
// 线程循环执行开始(方法)
// 重点:该方法就是子类需要实现的该线程中执行任务的方法,另外该线程的返回值有不同作用:
// 1)循环执行:若该方法返回true且未调用过requestExit()方法,则该方法将再次被调用执行即形成循环调用。
// 2)执行一次:若放回false,则该线程在该方法返回时将会退出。
// 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线程类对象之间进行赋值
Thread& operator=(const Thread&);
// 线程循环方法(主要是用于线程启动时传入的方法引用【指针】)
static int _threadLoop(void* user);
// 是否可以调用Java
const bool mCanCallJava;
// 线程ID信息,读写都需要加锁
// always hold mLock when reading or writing
thread_id_t mThread;
// 互斥锁【主要此处使用了mutable关键字来修饰该变量】
// 备注:被mutable修饰的变量,可以突破const的限制,在被const修饰的函数里面也能被修改。
mutable Mutex mLock;
// 线程退出条件变量
Condition mThreadExitedCondition;
// 线程状态
status_t mStatus;
// 是否该线程已请求退出(正在退出或已退出完成状态)
// 备注:
// volatile关键字可以用来提醒编译器它后面所定义的变量随时有可能改变,
// 因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。
// 如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,
// 如果这个变量由别的程序更新了的话,将出现不一致的现象。
// note that all accesses of mExitPending and mRunning need to hold mLock
volatile bool mExitPending;
// 是否线程正在运行
volatile bool mRunning;
// 缓存线程自身
sp<Thread> mHoldSelf;
#if defined(__ANDROID__)
// 若存在安卓平台宏定义,则进入此处
// 线程内核ID
// 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
};
} // namespace android
// ---------------------------------------------------------------------------
#endif // _LIBS_UTILS_THREAD_H
// ---------------------------------------------------------------------------
Thread类实现:
注意该类是在[system/core/libutils/Threads.cpp]文件中实现的,而没有Thread.cpp文件。
该文件内部还有其他功能实现,用到时会分析。
1、Thread类构造函数和析构函数实现分析:
构造函数:简单初始化参数而已
析构函数:空实现
// [system/core/libutils/Threads.cpp]
/*
* This is our thread object!
*/
// mCanCallJava 该参数的意思为是否调用java,若需要和java端交互则需要返回true
Thread::Thread(bool canCallJava)
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thread::mLock"),
mStatus(OK),
mExitPending(false),
mRunning(false)
#if defined(__ANDROID__)
,
mTid(-1)
#endif
{
}
Thread::~Thread()
{
}
2、readyToRun()方法实现分析:
执行一次初始化操作
也是一个空实现,返回成功,子类可重写
// [system/core/libutils/Threads.cpp]
status_t Thread::readyToRun()
{
return OK;
}
3、requestExit()方法实现分析:
只是简单的使用自动锁来修改【是否该线程已退出】标志位为true,即请求退出标识。
请求退出线程,该方法被调用后,这个线程仍可能还正在运行,该方法可以在多线程中调用。
// [system/core/libutils/Threads.cpp]
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
mExitPending = true;
}
4、run()方法实现分析:
启动线程运行处理
启动线程运行
该方法可只传入线程名 name,其他两个参数为默认值
priority:该参数表示当前线程的优先级别,主要用于CPU线程调用的处理
其取值范围常量定义在
stack:该参数表示线程大小
// [system/core/libutils/Threads.cpp]
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");
// 加锁【自动互斥锁】(内存屏障)
// 关于android的互斥锁和自动锁实现后续有时间再分析
Mutex::Autolock _l(mLock);
// 若正在运行则不处理,并返回无效操作码
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// 初始化值
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = OK;
mExitPending = false;
mThread = thread_id_t(-1);
// 缓存自身强引用
// hold a strong reference on ourself
mHoldSelf = this;
// 标记已正在运行状态中
mRunning = true;
// 这两个方法内部实现就是真正创建和启动该线程的处理,参数值一致
bool res;
if (mCanCallJava) {
// 需要调用java端时
// 见4.1小节分析
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
// 不需要调用java端时
// 见4.2小节分析
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
if (res == false) {
// 启动线程失败时,清除工作
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
// 将智能指针中的强引用清除
mHoldSelf.clear(); // "this" may have gone away after this.
return UNKNOWN_ERROR;
}
// 启动线程成功,返回成功
// Do not refer to mStatus here: The thread is already running (may, in fact
// already have exited with a valid mStatus result). The OK indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return OK;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
4.1、createThreadEtc(_threadLoop, this, name, priority, stack, &mThread)实现分析:
【需要调用java端时】
该方法其实是声明定义在【system/core/libutils/include/utils/AndroidThreads.h】中,其实它主要就是实现了一套分别用C和C++编译器编译方式来编译代码,即提供了C API和C++ API。
// [system/core/libutils/include/utils/AndroidThreads.h]
// 【thread_func_t】该参数由传入值【_threadLoop】可知是个方法指针,其声明定义见下面的分析
// 【userData】值由传入参数可知,其值为Thread类自身对象指针,此处转为无类型指针,其实它就是线程方法【_threadLoop】运行时获取到的参数值,熟悉POSIX线程使用的都清楚
// 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 = nullptr)
{
// 调用该方法
// 见下面的分析
return androidCreateThreadEtc(entryFunction, userData, threadName,
threadPriority, threadStackSize, threadId) ? true : false;
}
thread_func_t 线程方法声明和定义
// [system/core/libutils/include/utils/ThreadDefs.h]
typedef android_thread_func_t thread_func_t;
// [system/core/libutils/include/utils/ThreadDefs.h]
typedef int (*android_thread_func_t)(void*);
androidCreateThreadEtc实现分析:
其声明在:
其是C API部分的代码,但只是个引入外部定义实现
// [system/core/libutils/include/utils/AndroidThreads.h]
// Create thread with lots of parameters
extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
void *userData,
const char* threadName,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId);
外部定义实现在:
// [system/core/libutils/Threads.cpp]
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);
}
其调用了【gCreateThreadFn】全局创建线程方法:
// [system/core/libutils/Threads.cpp]
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
其定义为一个static文件内部可访问的全局变量,并且最终还是调用了4.2小节需要分析的方法。
因此此处我们可以进行【mCanCallJava】参数具体含义的小节:
该参数其实就是为了调用C++编译方式的API来代理调用C编译方式的API,最终创建该线程。
【此变量作用若有分析不太对的地方,还请多多指教】
4.2、androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread)实现分析:
【不需要调用java端时】
注意该方法在 [system/core/libutils/Threads.cpp] 该文件中有两个实现,一个是针对Window32平台的,另一个才是android需要的,由其实现可知,其实现实际上就是调用POSIX标准线程接口【其定义了创建和操纵线程的一套可移植系统API即实现了跨平台API】来实现的,关于POSIX接口的声明定义和简单实用可参考百度百科POSIX线程,如下
// [system/core/libutils/Threads.cpp]
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)
{
// 线程属性,主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。
pthread_attr_t attr;
// 初始化线程属性变量。运行后,pthread_attr_t结构所包含的内容是操作系统支持的线程的所有属性的默认值。
pthread_attr_init(&attr);
// 设置线程属性变量的detachstate(脱离调用线程独自运行)属性(决定线程在终止时是否可以被joinable)
// PTHREAD_CREATE_DETACHED:新线程与进程中其他线程脱离同步状态
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#if defined(__ANDROID__) /* valgrind is rejecting RT-priority create reqs */
// android平台的处理:线程优先级不是默认值或线程名不为空时进行处理
if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
// Now that the pthread_t has a method to find the associated
// android_thread_id_t (pid) from pthread_t, it would be possible to avoid
// this trampoline in some cases as the parent could set the properties
// for the child. However, there would be a race condition because the
// child becomes ready immediately, and it doesn't work for the name.
// prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
// proposed but not yet accepted.
// 一个简单结构存储设置的属性值
thread_data_t* t = new thread_data_t;
// 线程运行优先级
t->priority = threadPriority;
// 线程名【复制新字符串内存】
t->threadName = threadName ? strdup(threadName) : NULL;
// 线程方法指针【即函数地址】参数为【_threadLoop】
t->entryFunction = entryFunction;
// 线程方法参数
t->userData = userData;
// 注意:此处在android平台时,将传入的线程方法指针修改成了该类的该方法地址,
// 其实际上只是参数【_threadLoop】线程方法代理实现而已,主要是用于设置线程优先级和线程名
// 见4.2.1小节分析
entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
// 注意:此处在android平台时,将传入的Thread的类本身参数修改成
// 打包好的属性值结构对象,作为参数传递给线程接收方法
userData = t;
}
#endif
if (threadStackSize) {
// 不为0时,设置线程堆栈大小
pthread_attr_setstacksize(&attr, threadStackSize);
}
// 设置全局错误码为0
// errno 是记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义。
// 当linux C API函数发生异常时,
// 一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义
errno = 0;
// 线程句柄.出于移植目的,不能把它作为整数处理,应使用函数pthread_equal()对两个线程ID进行比较。
// 获取自身所在线程id使用函数pthread_self()
pthread_t thread;
// 创建新线程thread对象,在该线程中运行线程方法entryFunction,并传入参数userData
// 见4.2.2小节分析
int result = pthread_create(&thread, &attr,
(android_pthread_entry)entryFunction, userData);
// 删除线程的属性,用无效值覆盖
pthread_attr_destroy(&attr);
if (result != 0) {
ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
"(android threadPriority=%d)",
entryFunction, result, strerror(errno), threadPriority);
// 注意此处返回0是错误码,和一般C函数成功返回0不一样
return 0;
}
// Note that *threadID is directly available to the parent only, as it is
// assigned after the child starts. Use memory barrier / lock if the child
// or other threads also need access.
if (threadId != nullptr) {
// 直接修改了该指针(void *)指向的值即线程ID为thread强转为int值,
// 但也正如上面的说明,若需要移植则不能直接强转,
// 因此此处代码也有一行英文注释即该实现不可移植。
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
// 返回成功值为1,其实就是true
return 1;
}
4.2.1、(android_thread_func_t)&thread_data_t::trampoline实现分析代理线程方法:
在struct thread_data_t该结构中声明定义:
该方法处理实际上只是参数【_threadLoop】线程方法代理实现而已,主要是用于设置线程优先级和线程名
// [system/core/libutils/Threads.cpp]
// we use this trampoline when we need to set the priority with
// nice/setpriority, and name with prctl.
static int trampoline(const thread_data_t* t) {
thread_func_t f = t->entryFunction;
void* u = t->userData;
int prio = t->priority;
char * name = t->threadName;
// 释放new的内存
delete t;
// 设置线程优先级处理
setpriority(PRIO_PROCESS, 0, prio);
if (prio >= ANDROID_PRIORITY_BACKGROUND) {
set_sched_policy(0, SP_BACKGROUND);
} else {
set_sched_policy(0, SP_FOREGROUND);
}
if (name) {
// 设置线程名
// 见下面的分析
androidSetThreadName(name);
// 前面使用了strdup复制字符串,因此需要free释放其内存
free(name);
}
// 最终调用了真正的线程方法并传入了参数
return f(u);
}
androidSetThreadName实现分析:
调用prctl方法来实现的,不展开分析
// [system/core/libutils/Threads.cpp]
void androidSetThreadName(const char* name) {
#if defined(__linux__)
// Mac OS doesn't have this, and we build libutil for the host too
int hasAt = 0;
int hasDot = 0;
const char *s = name;
while (*s) {
if (*s == '.') hasDot = 1;
else if (*s == '@') hasAt = 1;
s++;
}
int len = s - name;
if (len < 15 || hasAt || !hasDot) {
s = name;
} else {
s = name + len - 15;
}
prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
#endif
}
4.2.1、线程方法(_threadLoop)实现分析:
由上分析可知,在线程运行时,首先会运行线程代理方法【thread_data_t::trampoline】,其会调用该方法执行。
// [system/core/libutils/Threads.cpp]
int Thread::_threadLoop(void* user)
{
// 传入的参数为this即Thread类对象自身指针
Thread* const self = static_cast<Thread*>(user);
// 转为智能指针
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
// 清空自身智能指针对象持有的指针及其指针计数
self->mHoldSelf.clear();
#if defined(__ANDROID__)
// android平台时,线程内核ID赋值,可用于debug
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {
// 第一次运行线程方法时
first = false;
// 由前面分析,可知该方法默认返回OK,子类可覆写做一些初始化工作
self->mStatus = self->readyToRun();
result = (self->mStatus == OK);
// exitPending() 方法见第5小节分析
if (result && !self->exitPending()) {
// 状态OK并且该线程未请求退出状态时,若已请求退出状态则不会运行
// 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);
// 检查线程循环方法返回值 或 是否已请求等待退出状态
if (result == false || self->mExitPending) {
// 若返回值false即要求不循环执行线程方法 或 请求线程退出时
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.
// 清空线程内核ID,可使 requestExitAndWait() 方法无效
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
// 唤醒请求了 requestExitAndWait() 或 join() 方法而等待该线程执行完成的其他线程。
// 注意此处发送的是一个唤醒广播,因此等待在该条件变量上的线程可以有多个
self->mThreadExitedCondition.broadcast();
break;
}
}
// 注意此处对强弱指针引用计数的处理,很有意思哟
// 清除(减少)强引用计数,并若为0则会进行释放内部实际对象强引用指针
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
strong.clear();
// 上面减少强引用计数处理后,可能其强引用计数不为0即大于0时
// (实际上就是创建该线程的地方还持有该线程的强引用指针,因此不为0),
// 那么就可以立即使用弱引用计数对象进行提升其为强引用(指针)对象,然后再次进行循环
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
// 判断强引用(指针)对象不为空则再次循环执行线程循环方法
} while(strong != nullptr);
return 0;
}
由上分析可知:readyToRun() 该方法只会运行一次,而实现类(即子类)线程方法可以运行循环运行。
注意:该线程实现其实还提供了多种线程运行方式:
(1)若想要不执行 threadLoop() 线程方法,在 readyToRun() 方法中合适的位置调用requestExit() 方法或 threadLoop() 方法返回false。
(2)若只想只想一次 threadLoop() ,则在threadLoop() 方法中合适的位置调用requestEixt()方法或 threadLoop() 方法返回false。
(3)循环执行 threadLoop() 功能,只需重写 threadLoop() 方法返回false即可。
注:以上三种运行模式中 readyToTun() 都(只)会运行一次。
并且上面的实现对强弱指针引用计数的处理,很有意思哟。这就是对循环执行中释放内存不造成内存泄漏处理的关键地方。
5、exitPending()实现分析:
其实就是在第3小节分析可改变该值,返回【是否该线程已退出】标志位
// [system/core/libutils/Threads.cpp]
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
return mExitPending;
}
6、requestExitAndWait()实现分析:
请求退出并等待退出完毕后该方法才返回(调用端),
即该方法会阻塞调用端线程,直到彻底退出后才返回。
警告:必须小心调用该方法,避免造成死锁,即千万别在当前线程中调用该方法,否则会返回错误状态(WOULD_BLOCK)
// [system/core/libutils/Threads.cpp]
status_t Thread::requestExitAndWait()
{
Mutex::Autolock _l(mLock);
// 判断当前缓存的线程ID和真正的当前线程ID是否一致
// getThreadId()见下面的分析
if (mThread == getThreadId()) {
// 若一致则表明该方法是在当前线程(方法)中调用的,
// 但该方法不允许自身线程调用,只运行其他线程调用,为了避免死锁。
ALOGW(
"Thread (this=%p): don't call waitForExit() from this "
"Thread object's thread. It's a guaranteed deadlock!",
this);
// 返回该错误码
return WOULD_BLOCK;
}
// 请求退出等待,设置该状态值
mExitPending = true;
// 若正在运行则执行线程退出条件变量的wait锁等待(当前线程的执行完毕)
// 若线程未开始运行或已退出运行,则该方法会立即返回
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}
// 这个注释:其实意思就是这行代码在此处可能不需要,可以去掉,不过由于历史遗留原因,则这么做了。也可以去掉。
// This next line is probably not needed any more, but is being left for
// historical reference. Note that each interested party will clear flag.
mExitPending = false;
// 返回当前线程状态【注意该状态,若线程已退出状态也是返回成功OK的】
return mStatus;
}
getThreadId()实现分析:
// [system/core/libutils/include/utils/AndroidThreads.h]
// Get some sort of unique identifier for the current thread.
inline thread_id_t getThreadId() {
return androidGetThreadId();
}
// [system/core/libutils/Threads.cpp]
android_thread_id_t androidGetThreadId()
{
// 可以知道该方法值获取 POSIX 线程标准库中的线程内核ID
return (android_thread_id_t)pthread_self();
}
7、join() 实现分析:
等待线程(阻塞运行完毕),即该方法调用后会阻塞调用端线程,等待该线程执行完毕退出才返回调用端。
阻塞当前的(调用)线程,直到另外一个线程运行结束。
注意:若该线程未启动,则会立即返回。
警告:不要在该线程中调用该方法,否则会返回错误状(WOULD_BLOCK)。
注意该方法和【requestExitAndWait()】方法的区别在于,join() 方法会一直等待,不会主动请求结束线程的循环执行。即如果循环执行功能开启的话,该方法将一直等待下去,直到线程被执行了退出。
// [system/core/libutils/Threads.cpp]
status_t Thread::join()
{
Mutex::Autolock _l(mLock);
// 判断当前缓存的线程ID和真正的当前线程ID是否一致
if (mThread == getThreadId()) {
// 同上,不能在该线程中调用该方法
ALOGW(
"Thread (this=%p): don't call join() from this "
"Thread object's thread. It's a guaranteed deadlock!",
this);
return WOULD_BLOCK;
}
// 若正在运行则执行线程退出条件变量的wait锁等待(当前线程的执行完毕)
// 若线程未开始运行或已退出运行,则该方法会立即返回
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}
return mStatus;
}
8、isRunning() 实现分析:
是否该线程正在运行
// [system/core/libutils/Threads.cpp]
bool Thread::isRunning() const {
Mutex::Autolock _l(mLock);
return mRunning;
}
9、getTid() 获取线程内核ID
若是android平台,则提供该方法
// [system/core/libutils/Threads.cpp]
#if defined(__ANDROID__)
pid_t Thread::getTid() const
{
// mTid is not defined until the child initializes it, and the caller may need it earlier
Mutex::Autolock _l(mLock);
pid_t tid;
// 判断此时线程是否已运行
if (mRunning) {
// 将android线程ID强转为 POSIX标准的线程对象,
// 因为上面分析的创建流程中就是将该POSIX线程对象强转为android线程ID值来缓存的。
// android_thread_id_t_to_pthread该方法实现见下面的分析
pthread_t pthread = android_thread_id_t_to_pthread(mThread);
tid = pthread_gettid_np(pthread);
} else {
// 注意:若未开始运行则返回-1
ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
tid = -1;
}
return tid;
}
#endif
android_thread_id_t_to_pthread() 实现分析:
// [system/core/libutils/Threads.cpp]
#if defined(__ANDROID__)
static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
{
// 直接强转
return (pthread_t) thread;
}
#endif
本章结束
通过分析我们可以更直观和更清楚的理解底层线程真正的实现和处理流程。也能帮助我们更快更正确的使用底层线程功能来实现自己的业务逻辑和功能。