[정수리] 안드로이드 개발의 Thread 클래스 분석

Linux 시스템에서 스레드 함수 생성: pthreadcreate (), 안드로이드에서 우리는 라인에 클래스 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 androidcreate_thread_fn gCreateThreadFn = androidCreateRawThreadEtc; 여기에 기본값은androidCreateRawThreadEtc입니다. 이것은 앞에서 호출한 것과 같습니다???
함수 포인터라면 값을 부여할 곳이 있을 것이다.
void androidSetCreateThreadFunc(android_create_thread_fn func)
{
	gCreateThreadFn = func;
}

그럼 이 함수는 어디에서 호출되었습니까?또 무슨 값을 매겼을까?Android Runtime 클래스에서 가상 머신을 시작하는 위치를 찾았습니다.
int androidRuntime::startReg(JNIEnv* env)
{
	androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
	return 0;
}

이렇게 하면 mCanCall Java가 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);
}

마지막으로 호출된 것은 같은 라인을 만드는 함수입니다. 리셋 함수만 다릅니다. 여기는 안드로이드 런타임::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 함수는 호출하기 전에 자바 AttachThread () 를 호출하여 루트attach를 JNI 환경으로 가져갔습니다. 그러면 루트 함수는 JNI 함수를 호출할 수 있고, 마지막 루트 함수는 종료한 후에 자바 DetachThread () 를 호출하여 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()  ,    

좋은 웹페이지 즐겨찾기