以一个例子分析。
class DoCaptureThread : public Thread {
V4L2CameraDevice* mV4l2CameraDevice;
bool mRequestExit;
public:
DoCaptureThread(V4L2CameraDevice* dev) :
Thread(false),
mV4l2CameraDevice(dev),
mRequestExit(false) {
}
void startThread() {
run("CameraCaptureThread", PRIORITY_URGENT_DISPLAY);
}
void stopThread() {
mRequestExit = true;
}
virtual bool threadLoop() {
if (mRequestExit) {
return false;
}
return mV4l2CameraDevice->captureThread();
}
};
这个用法其实挺简单的,就是创建一个captureThread。
封装run函数,也就是thread name以及priority。
重写threadLoop,添加了一个退出变量。不懂为啥不用requestExit函数。。。
那么使用的时候,
1,先创建
mCaptureThread = new DoCaptureThread(this);
2,mCaptureThread->startThread(); //开启线程 run函数会调用,_threadloop,_threadloop会循环调用threadLoop.
3,mCaptureThread->stopThread();// 让threadLoop返回false,退出线程循环。
看一下Thread基类的定义。
http://androidxref.com/6.0.0_r1/xref/system/core/include/utils/Thread.h
http://androidxref.com/6.0.0_r1/xref/system/core/libutils/Threads.cpp
class Thread : virtual public RefBase
{
public:
// Create a Thread object, but doesn't create or start the associated
// thread. See the run() method.
Thread(bool canCallJava = true);
virtual ~Thread();
// Start the thread in threadLoop() which needs to be implemented.
virtual status_t run( const char* name = 0,
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();
// 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();
// Wait until this object's thread exits. Returns immediately if not yet runnin
// 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;
#ifdef HAVE_ANDROID_OS
// 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:
// 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& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
// always hold mLock when reading or writing
thread_id_t mThread;
mutable Mutex mLock;
Condition mThreadExitedCondition;
status_t mStatus;
// note that all accesses of mExitPending and mRunning need to hold mLock
volatile bool mExitPending;
volatile bool mRunning;
sp
#ifdef HAVE_ANDROID_OS
// 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
};
/*
* This is our thread object!
*/
Thread::Thread(bool canCallJava)
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thread::mLock"),
mStatus(NO_ERROR),
mExitPending(false), mRunning(false)
#ifdef HAVE_ANDROID_OS
, mTid(-1)
#endif
{
}
Thread::~Thread()
{
}
status_t Thread::readyToRun()
{
return NO_ERROR;
}
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
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 = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
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; // 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 NO_ERROR indication
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return NO_ERROR;
// Exiting scope of mLock is a memory barrier and allows new thread to run
}
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast
sp
wp
self->mHoldSelf.clear();
#ifdef HAVE_ANDROID_OS
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
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);
if (result == false || self->mExitPending) {
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.
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
self->mThreadExitedCondition.broadcast();
break;
}
}
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
strong.clear();
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
} while(strong != 0);
return 0;
}
void Thread::requestExit()
{
Mutex::Autolock _l(mLock);
mExitPending = true;
}
status_t Thread::requestExitAndWait()
{
Mutex::Autolock _l(mLock);
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;
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;
return mStatus;
}
status_t Thread::join()
{
Mutex::Autolock _l(mLock);
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;
}
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}
return mStatus;
}
bool Thread::isRunning() const {
Mutex::Autolock _l(mLock);
return mRunning;
}
#ifdef HAVE_ANDROID_OS
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) {
pthread_t pthread = android_thread_id_t_to_pthread(mThread);
tid = pthread_gettid_np(pthread);
} else {
ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
tid = -1;
}
return tid;
}
#endif
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
return mExitPending;
}