现在的位置: 首页 > 综合 > 正文

Android开发之Thread类分析

2018年04月04日 ⁄ 综合 ⁄ 共 4782字 ⁄ 字号 评论关闭

        在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create()
当我们想创建线程的时候,只需要继承于这个Thread类并实现虚函数thread_loop()即可。

frameworks/base/include/utils/threads.h
class Thread : virtual public RefBase
{
public:
	// 创建一个Thread对象,但是并不立即启动线程函数
	Thread(bool canCallJava = true);
	virtual ~Thread();
	// 开始启动线程函数,调用的是threadLoop
	virtual status_t run(const char*name = 0, int32_t prority = PRIORITY_DEFAULT,
				size_t stack = 0);
	// 申请退出这个线程
	virtual void requestExit();
	virtual status_t readyToRun();
	// 调用requestExit()等待直到这个线程退出
		status_t requestExitAndWait();
	// 等待直到线程退出,如果没有启动立即返回
		status_t join();
protected:
	// 如果调用了requestExit()返回true
	bool exitPending() const;
private:
	// 这是实际的线程函数,继承类必须实现它,
	// 返回true的话再次调用,返回false的话就会退出
	virtual bool threadLoop() = 0;
	// 禁止赋值
	Thread& operator = (const Thread&);
	// 内部类,被run函数调用,实际调用threadLoop
	static int _threadLoop(void* user);
	const bool mCanCallJava;
		thread_id_t mThread;	// thread_id_t 其实是 void*类型
	mutable Mutex mLock;
		Condition mThreadExitedCondition;
		status_t mStatus;
	// 注意:所以操作这两个变量的地方都需要上锁
	volatile bool mExitPending;
	volatile bool mRunning;
		sp<Thread> mHoldSelf;
};

我们首先看下Thread类的构造函数:

Thread::Thread(bool canCallJava) 
	:	mCanCallJava(canCallJava),
		mThread(thread_id_t(-1)),
		mLock("Thrad::mLock"),
		mStatus(NO_ERROR),
		mExitPending(false), mRunnig(false)
{}

真正启动线程的函数:

status_t Thread::run(const char*name, int32_t priority, size_t stack)
{
	Mutex::Autolock _l(mLock);
	if(mRunnig)
		return INVALID_OPERATION;
	mState = NO_ERROR;
	mExitPending = false;
	mThread = thread_id_t(-1);
	mHoldSelf = this;	// 保存着当前对象的引用
	mRunning = true;
	if (mCanCallJava) 
		res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);
	else
		res = androidCreateRawThreadEtc(_threadLoop, this, name, 
				priority, stack, &mThread);
	if(res == false) {
		mStatus = UNKNOWN_ERROR;
		mRunning = false;
		mThread = thread_id_t(-1);
		mHoldSelf.clear();
		return UNKNOWN_ERROR;
	}
	return NO_ERROR;
}
这里有个判断mCanCallJava是个什么东西?接着往下看
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;
}		
int androidCreateThreadEtc(thread_func_t entryFunction, 
			void* userData,
			const char* threadName,
			int32_t threadPriority = PRIORITY_DEFAULT,
			size_t threadStackSize = 0,
			thread_id_t *threadId = 0)
{
	return gCreateThreadFn(entryFunction, userData, threadName, threadPriority,
		threadStackSize, threadId);
}

我们看到最后调用的是gCreateThreadFn这个函数,而gCreateThreadFn是个全局的函数指针,
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
这里默认给它赋值为 androidCreateRawThreadEtc,这跟前面调用的是一样的???

既然是函数指针肯定有给它赋值的地方:

void androidSetCreateThreadFunc(android_create_thread_fn func)
{
	gCreateThreadFn = func;
}

那这个函数在什么地方调用的呢?又给它赋什么值了呢?
我们找到了再AndroidRuntime类里面启动虚拟机的地方:

int androidRuntime::startReg(JNIEnv* env)
{
	androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
	return 0;
}

这样如果我们的mCanCallJava如果为true的话,调用的就是:

int AndroidRuntime::javaCreateThreadEtc(android_thread_func_t entryFunction,
				void* userData,
				const char* threadName,
				int32_t threadPriority,
				suze_t threadStackSize,
				android_thread_id_t *threadId)
{
	void** args = (void**)malloc(3*sizeof(void*));
	args[0] = (void*)entryFunction;
	args[1] = userData;
	args[2] = (void*)strdup(threadName);
	return androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args.
		threadName, threadPriority, threadStackSize, threadId);
}

最后调用的还是同一个创建线程的函数只是回调函数不一样,这里变成了AndroidRuntime::javaThreadShell

int AndroidRuntime::javaCreateThreadEtc(void* args)
{
	voir* start = ((void**)args)[0];
	voir* userData = ((void**)args)[1];
	voir* name = ((void**)args)[2];
	free(args);
	JNIEnv* env;
	
	javaAttachThread(name, &env);
	result = (*(android_thead_func_t)start)(userData);
	javaDetachThread();
	
	free(name);
	return result;
}

这里线程函数javaThreadShell里面还是调用前面我们的_threadLoop函数,只不过在调用之前,调用
了javaAttachThread()将线程attach到JNI环境中去了,这样线程函数就可以调用JNI函数,最后线程
函数退出之后再调用javaDetachThread()退出JNI环境。

现在进入线程函数_threadLoop(),这是一个static函数

int Thread::_threadLoop(void* user)
{
	Thread* const self = static_cast<Thread*>(user);
	sp<Thead> strong(self->mHoldSelf);
	wp<Thead> weak(strong);
	self->mHoldSelf.clear();
	
	bool first = true;
	
	do {	// 进入一个循环,通过判断返回值和内部退出标志位决定是否退出线程
		bool result;
		if (fisr) {
			first = false;
			self->mStatus = self->readyToRun();
			result = (self->mStatus == NO_ERROR);
			if (result && !self->exitPendind()) {	// 检查是否退出
				result = self->threadLoop();	// 调用实际线程函数
			}
		} else {
			result = self->threadLoop();
		}
		
		{
			Mutex::Autolock _l(self->mLock);
			if (result == false || self->mExitPending) {
				self->mExitPending = true;
				self-mRunning = false;
				self->mThread = thread_ir_t(-1);
				self->mThreadExitedCondition.broadcast();
				break;
			}
		
		}
		strong.clear();
		strong = weak.promote();
	} while(strong != 0);
	return 0;
}

在这里线程退出的条件为:
1)result = true 意味着子类在实现的threadLoop函数中返回false,这样线程就主动退出了
2)mExidPendding = true 这个变量值由Thread类的requestExit函数设置,这样线程就被动退出了。
最后如果线程退出了需要进行些去初始化操作,设置线程运行状态,广播告知其他关心这个线程的对象。

最后,如果我们想使用线程类:
1)创建一个类如MyThread,继承与Thead类
2)在MyThread类中实现父类的纯虚函数threadLoop,也就是我们调用pthread_create时传入的线程函数。
3)定义一个MyThread变量 thread,调用线程的run()方法,启动函数

抱歉!评论已关闭.