• [置顶] Android开发之Thread类分析


            在我们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,调用线程的start()方法,启动函数
  • 相关阅读:
    GITHUB随笔 15-5月 junit
    github心得
    (转)哪个瞬间让你突然觉得逛知乎真有用?
    0-1背包问题(the knapsack problem)
    对VSCode在安装了Dev-cpp的电脑上的配置
    非全日制考研资料(未完待续)
    CSS那些事读书笔记-2
    CSS那些事读书笔记-1
    前端面试准备-1
    工作日记-一个有趣的定时任务实现
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3235285.html
Copyright © 2020-2023  润新知