【android12】【AHandler】【4.AHandler原理篇ALooper类方法全解】

news2024/11/5 17:23:01

AHandler系列

【android12】【AHandler】【1.AHandler异步无回复消息原理篇】-CSDN博客

【android12】【AHandler】【2.AHandler异步回复消息原理篇】-CSDN博客

【android12】【AHandler】【3.AHandler原理篇AHandler类方法全解】-CSDN博客

其他系列

本人系列文章-CSDN博客


1.简介

前面我们主要介绍了有回复和无回复的消息的使用方法和源码解析,为了更好的理解Ahandler这个类的作用,本篇便主要对AHandler类的所有方法进行全解。

简单介绍一下Ahandler机制

AHandler是Android native层实现的一个异步消息机制,在这个机制中所有的处理都是异步的,将消息封装到一个消息AMessage结构体中,然后放到消息队列中去,后台专门有一个线程ALooper会从这个队列中取出消息然后分发执行,执行函数就是AHandler实例的onMessageReceived。

在AHandler中的消息分为不需要回复的消息和需要回复的消息。

不需要回复的消息:当被post到消息队列后,Alooper会从消息队列中取出消息,并发送给相应的Ahandler的onMessageReceived进行处理。

需要回复的消息:当被post到消息队列后,Alooper会从消息队列中取出消息,并发送给相应的Ahandler的onMessageReceived进行处理,处理完后,Ahandler会将想回复的消息返回给发送方,发送方接受返回的response消息。

1.1 主要类及其作用

AHandler:处理类,用于消息的处理,有一个纯虚函数onMessageReceived,一般需要继承此类并重写此方法,用于接受和处理消息。

AMessage:消息类,用于构建各种消息,通过post方法将消息发送给Alooper

Alooper:轮询类,用于保存消息队列,然后将消息发送到对应的AHandler

AReplyToken:这类似一个标识,表示要回复的是哪一条消息

 1.2 Alooper类图

2.源码解析

2.1 Alooper类

//Alooper.h分析
struct ALooper : public RefBase {
    typedef int32_t event_id;
    typedef int32_t handler_id;

    ALooper();

    void setName(const char *name);//设置looper的名称

    handler_id registerHandler(const sp<AHandler> &handler);//注册Handler,用map保存hadnler_id和handler信息
    void unregisterHandler(handler_id handlerID);//取消注册handler

    status_t start(bool runOnCallingThread = false,bool canCallJava = false,int32_t priority = PRIORITY_DEFAULT);//让Alooper线程运行起来

    status_t stop();//让Alooer线程停止运行

    static int64_t GetNowUs();//获取当前时间

    const char *getName() const {//获取当前Alooper的名称
        return mName.c_str();
    }

protected:
    virtual ~ALooper();//虚析构

private:
    friend struct AMessage;//友元结构体

    struct Event {int64_t mWhenUs;sp<AMessage> mMessage;};//存储Amessage的消息。

    Mutex mLock;//锁
    Condition mQueueChangedCondition;//条件变量,用于唤醒线程

    AString mName;//Alooper的名称

    List<Event> mEventQueue;//消息队列,会根据等待时间来从小到大排序

    struct LooperThread;//此处是声明。
    sp<LooperThread> mThread;//智能指针指向LooperThread
    bool mRunningLocally;//线程是否在运行

    //使用单独的锁进行回复的处理,因为它总是在另一个线程上。但是,使用中心锁可以避免为每个回复创建mutex 
    Mutex mRepliesLock;
    Condition mRepliesCondition;


	//发送一个消息到Aloope中
    void post(const sp<AMessage> &msg, int64_t delayUs);

    // 创建一个和当前looper一起使用的AReplyToken,AReplyToken主要用于回复消息
    sp<AReplyToken> createReplyToken();
    //发送方用于等待回复的消息
    status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);

	
	//接收方向发送方回复消息
    status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);


    bool loop();//死循环,不断的从消息队列中取出消息。

    DISALLOW_EVIL_CONSTRUCTORS(ALooper);
};

2.2 ALooper::GetNowUs

// static
int64_t ALooper::GetNowUs() {//获取当前时间
    return systemTime(SYSTEM_TIME_MONOTONIC) 
}

2.3 ALooper::ALooper构造函数

会清除旧的Ahandler

ALooper::ALooper()
    : mRunningLocally(false) {
    gLooperRoster.unregisterStaleHandlers();//清除旧的Ahandler。从保存注册Ahandler的列表中删除
}

2.4 析构函数

调用stop函数,让looper线程停止循环,并释放线程资源

ALooper::~ALooper() {
    stop();
}

2.5 ALooper::setName

void ALooper::setName(const char *name) {//为looper设置名称
    mName = name;
}

2.6 ALooper::registerHandler

注册Ahandler并将其保存到一个容器中。

ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {//注册Ahandler,用一个map保存alooper和Ahandler的对应关系
    return gLooperRoster.registerHandler(this, handler);
}
ALooper::handler_id ALooperRoster::registerHandler(const sp<ALooper> &looper, const sp<AHandler> &handler) {
    Mutex::Autolock autoLock(mLock);

    if (handler->id() != 0) {//此时handler->id()等于0
        CHECK(!"A handler must only be registered once.");
        return INVALID_OPERATION;
    }

    HandlerInfo info;
	//定义是struct HandlerInfo {
    //wp<ALooper> mLooper;
    //wp<AHandler> mHandler;
    //};
    info.mLooper = looper;//赋值looper
    info.mHandler = handler;//赋值handler
    ALooper::handler_id handlerID = mNextHandlerID++;//mNextHandlerID在构造函数是1,此时handler_id值是1,mNextHandlerID变为2
    mHandlers.add(handlerID, info);//保存信息KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;

    handler->setID(handlerID, looper);//此时handlerID等于1,handler持有looper的弱引用

    return handlerID;
}

2.7 ALooper::unregisterHandler

取消注册Ahandler,从容器中删除此Ahandler

void ALooper::unregisterHandler(handler_id handlerID) {//取消注册handler
    gLooperRoster.unregisterHandler(handlerID);
}
void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
    Mutex::Autolock autoLock(mLock);

    ssize_t index = mHandlers.indexOfKey(handlerID);//获取handlerID对应的位置

    if (index < 0) {
        return;
    }

    const HandlerInfo &info = mHandlers.valueAt(index);

    sp<AHandler> handler = info.mHandler.promote();

    if (handler != NULL) {//如果handler存在,则设置其id为0
        handler->setID(0, NULL);
    }

    mHandlers.removeItemsAt(index);//移除此handler
}

2.8 ALooper::start

主要作用为:

1.创建了一个LooperThread类对象,此类对象会创建一个线程

2.让线程运行起来。

//如果runOnCallingThread表示,是否开启新的线程
//如果runOnCallingThread = true:那么当前线程不会再做其它工作,陷入一个死循环。用于循环执行loop()函数。
//如果runOnCallingThread = false:会创建一个子线程,并将loop()逻辑放到这个特定子线程中处理。
status_t start(bool runOnCallingThread = false,bool canCallJava = false,int32_t priority = PRIORITY_DEFAULT);
status_t ALooper::start(bool runOnCallingThread, bool canCallJava, int32_t priority) {//传入的runOnCallingThread=false,canCallJava=false,priority优先级PRIORITY_DEFAULT
     if (runOnCallingThread) {//如果不创建新的线程,则当前线程死循环调用loop
         {
             Mutex::Autolock autoLock(mLock);

             if (mThread != NULL || mRunningLocally) {
                 return INVALID_OPERATION;
             }

             mrunninglocally = true;//mrunninglocally 为true意味着当前线程陷入loop的死循环
         }

       do {
         } while (loop());

         return ok;
     }

    Mutex::Autolock autoLock(mLock);

    if (mThread != NULL || mRunningLocally) {//此时mThread为空
        return INVALID_OPERATION;//无效操作
    }

    mThread = new LooperThread(this, canCallJava);//this是ALooper指针对象,canCallJava是false,new了一个继承自Thread的类

    status_t err = mThread->run(mName.empty() ? "ALooper" : mName.c_str(), priority);//让线程跑起来。传递的参数应该是ALooper,priority为PRIORITY_DEFAULT
	//线程的threadLoop方法会执行
    if (err != OK) {
        mThread.clear();
    }

    return err;
}

此函数的后续流程如下:

 2.8.1 LooperThread 构造函数

struct ALooper::LooperThread : public Thread {
    LooperThread(ALooper *looper, bool canCallJava): Thread(canCallJava),mLooper(looper),mThreadId(NULL) {}
//this是ALooper指针对象,canCallJava是false
}

 2.8.2  LooperThread构造函数

struct ALooper::LooperThread : public Thread {
    LooperThread(ALooper *looper, bool canCallJava): Thread(canCallJava),mLooper(looper),mThreadId(NULL) {}
//this是ALooper指针对象,canCallJava是false
}

2.8.3 Thread构造函数

Thread::Thread(bool canCallJava): 
	mCanCallJava(canCallJava),//canCallJava此时传入的是false
	mThread(thread_id_t(-1)),//定义类型是thread_id_t mThread;,代表线程id,
	//typedef android_thread_id_t thread_id_t;typedef void* android_thread_id_t;所以android_thread_id_t是一个void*的指针。
      mLock("Thread::mLock"),//互斥量
      mStatus(OK),
      mExitPending(false),
      mRunning(false)//表示此线程是否正在运行
#if defined(__ANDROID__)
      ,
      mTid(-1)
#endif
{
}

2.8.4 Thread::run

主要作用为:

1.调用androidCreateRawThreadEtc方法,此方法通过pthread创建了一个线程,并使线程分离,并执行_threadLoop方法

status_t Thread::run(const char* name, int32_t priority, size_t stack)
//此时传入的参数是name = Alooper,
//stack默认是0,priority为PRIORITY_DEFAULT
{
    Mutex::Autolock _l(mLock);
    /*
    if (mRunning) {//此时为false
        // thread already started
        return INVALID_OPERATION;//表示线程已经start
    }
*/

	//重置status和exitPending为其默认值,
    mStatus = OK;
    mExitPending = false;
    mThread = thread_id_t(-1);

    //持有自己的强引用
    mHoldSelf = this;//定义是sp<Thread>  mHoldSelf; this 是当前mThread线程对象

    mRunning = true;

    bool res;
    if (mCanCallJava) {//此时是false
        res = createThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);
		//此处的作用是通过pthread创建了一个线程,并使线程分离,并执行_threadLoop方法
    }

    // 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;
    // }

    return OK;
}

2.8.5 androidCreateRawThreadEtc

主要作用为:

1.通过pthread_create创建一个分离的线程,并执行_threadLoop方法

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)
							   //entryFunction是_threadLoop函数,android_thread_func_t是一个函数指针
							   //定义是typedef int (*android_thread_func_t)(void*);
							   //userData是Thread的类的指针的对象
							   //__android_unused是Alooper
							   //threadPriority为PRIORITY_DEFAULT
							   //threadStackSize是0
							   //threadId = -1
{
    pthread_attr_t attr;//创建线程属性变量
    pthread_attr_init(&attr);//初始化线程属性
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);设置线程属性是否分离。PTHREAD_CREATE_DETACHED为分离

#if defined(__ANDROID__)  /* valgrind is rejecting RT-priority create reqs */
/*
    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;
        t->entryFunction = entryFunction;
        t->userData = userData;
        entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
        userData = t;
    }*/
#endif

    // if (threadStackSize) {//此时是0,不设置
        // pthread_attr_setstacksize(&attr, threadStackSize);//设置线程属性中线程栈的大小
    // }

    errno = 0;
    pthread_t thread;
    int result = pthread_create(&thread, &attr,(android_pthread_entry)entryFunction, userData);//attr是线程属性。
	//entryFunction是线程要执行的函数_threadLoop,userData是Thread的强引用对象
    pthread_attr_destroy(&attr);//创建线程完成后,可以销毁属性。
    if (result != 0) {
        ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
             "(android threadPriority=%d)",
            entryFunction, result, strerror(errno), threadPriority);
        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) {
        *threadId = (android_thread_id_t)thread; // XXX: this is not portable
    }
    return 1;
}

2.8.6 _threadLoop

主要作用为:

1.死循环调用继承类的threadLoop方法,当threadLoop方法返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数

int Thread::_threadLoop(void* user)//此处传入的是Thread强引用对象
{
    Thread* const self = static_cast<Thread*>(user);//将void*类的指针转化为Thread*

    sp<Thread> strong(self->mHoldSelf);//获取Thread的强引用,此处是self->mHoldSelf是sp类型,故此处是拷贝构造,指向的对象引用会是2
    wp<Thread> weak(strong);//获取弱引用
    self->mHoldSelf.clear();//让强引用减一

#if defined(__ANDROID__)
    // 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();//此处就是返回一个ok
            result = (self->mStatus == OK);

            if (result && !self->exitPending()) {
                result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。
			//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法
            }
        } else {
            result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。
			//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法
        }

        // establish a scope for mLock
        {
        Mutex::Autolock _l(self->mLock);
        if (result == false || self->mExitPending) {//一般result都是true,self->mExitPending默认是false,
		//表示是否退出,在requestExit函数和requestExitAndWait函数中会设置为true
            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
            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();//mThreadExitedCondition是Condition类对象。
			//底层调用了pthread_cond_broadcast,唤醒所有在此conditon等待的线程
            break;
        }
        }

        // Release our strong reference, to let a chance to the thread
        // to die a peaceful death.
        strong.clear();//短暂的让强指针引用-1,以便有机会让线程释放。
        // And immediately, re-acquire a strong reference for the next loop
        strong = weak.promote();//立即获取强引用
    } while(strong != nullptr);//死循环

    return 0;
}

2.8.7 LooperThread::threadLoop

//线程调用run方法后,会调用threadLoop方法,当其返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数
struct ALooper::LooperThread : public Thread {
virtual bool threadLoop() {return mLooper->loop();}
}

2.8.8 ALooper::loop

此函数后续仍会遇见,我们现在只介绍当前的作用。

此时,looper刚启动,所以其消息队列中的消息为空,故此时是线程在条件变量上进行了等待。

当另外一个线程生成AMessage消息,并post时,会将此消息post到消息队列中,然后唤醒此looper线程,此时消息队列存在消息,会取出消息,并执行deliver函数去运输消息,最后会执行此消息。

bool ALooper::loop() {
    Event event;//event结构体为
	 //struct Event {
     //int64_t mWhenUs;
     //sp<AMessage> mMessage;
	 //};

    {
        Mutex::Autolock autoLock(mLock);
        if (mThread == NULL && !mRunningLocally) {//此时mThread不为空,mRunningLocally值为flase
            return false;
        }
        if (mEventQueue.empty()) {//此时消息队列应该是空的
            mQueueChangedCondition.wait(mLock);//此处定义是Condition mQueueChangedCondition;此线程阻塞在这里等待。
			//调用的是inline status_t Condition::wait(Mutex& mutex) {return -pthread_cond_wait(&mCond, &mutex.mMutex);}
            return true;
		//后面暂时不执行
        // }
        // int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
        // int64_t nowUs = GetNowUs();

        // if (whenUs > nowUs) {
            // int64_t delayUs = whenUs - nowUs;
            // if (delayUs > INT64_MAX / 1000) {
                // delayUs = INT64_MAX / 1000;
            // }
            // mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);

            // return true;
        // }

        // event = *mEventQueue.begin();
        // mEventQueue.erase(mEventQueue.begin());
    // }

    // event.mMessage->deliver();

    // // NOTE: It's important to note that at this point our "ALooper" object
    // // may no longer exist (its final reference may have gone away while
    // // delivering the message). We have made sure, however, that loop()
    // // won't be called again.

    // return true;
}
}
}

2.9 ALooper::stop

 此函数内部主要会调用调用requestExit方法。此方法会将一个线程循环的flag标志设置为true,等到下一次线程循环的时候,线程便会退出循环,然后释放线程资源。

status_t ALooper::stop() {
    sp<LooperThread> thread;
    bool runningLocally;

    {
        Mutex::Autolock autoLock(mLock);

        thread = mThread;//拷贝构造,使得强引用计数+1了
        runningLocally = mRunningLocally;
        mThread.clear();//强引用计数减1
        mRunningLocally = false;
    }

    if (thread == NULL && !runningLocally) {
        return INVALID_OPERATION;
    }

    if (thread != NULL) {//停止线程
        thread->requestExit();//调用requestExit方法。查看Thread类的结构可知,mExitPending = true会设置为true
    }
.
    mQueueChangedCondition.signal();//通知信号量等待的线程。然后会结束死循环。线程分离会自动销毁。
    {
        Mutex::Autolock autoLock(mRepliesLock);
        mRepliesCondition.broadcast();//广播唤醒在mRepliesCondition等待的所有线程
    }

    if (!runningLocally && !thread->isCurrentThread()) {
        // If not running locally and this thread _is_ the looper thread,
        // the loop() function will return and never be called again.
		//如果不是在本地运行,并且此线程_is_为looper线程,则loop()函数将返回并且不再被调用。
        thread->requestExitAndWait();
    }

    return OK;
}

此函数的后续流程为:

2.9.1 Thread::requestExit

设置mExitPending的标志位为true,线程就会退出循环,然后释放线程资源

//requestExit() 请求退出线程,立即返回。
void Thread::requestExit()
{
    Mutex::Autolock _l(mLock);
    mExitPending = true;//设置mExitPending的值为true,此时_threadLoop会执行下面的代码块。然后退出循环。然后由于线程是分离的,_threadLoop函数执行完,会自动回收。
}

 2.9.2 Thread::requestExitAndWait

当我们调用stop的时候是在A线程中,当我们设置mExitPending为ture后,表示要释放之前创建的分离的looper线程,而此时A线程需要等待looper线程释放完相关资源后,再往下走。

status_t Thread::requestExitAndWait()
{
    Mutex::Autolock _l(mLock);
    if (mThread == getThreadId()) {//如果是之前使用当前线程作为处理消息的线程,而不是新创建了一个线程。
	//那么此时自己调用requestExitAndWait,需要返回,不需要在下面mThreadExitedCondition条件变量上进行等待,因为只有一个线程,
	//此时线程会一直等待,因为没有其他线程唤醒。
        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;
}

2.9.3 _threadLoop

此时我们需要回到looper线程的这个函数,此时self->mExitPending为ture,然后当前线程会退出死循环,清除线程的id,同时唤醒之前等待的A线程。由于是分离的线程,故此时分离的线程会自动释放资源。

int Thread::_threadLoop(void* user)//此处传入的是Thread强引用对象
{
    Thread* const self = static_cast<Thread*>(user);//将void*类的指针转化为Thread*

    sp<Thread> strong(self->mHoldSelf);//获取Thread的强引用,此处是self->mHoldSelf是sp类型,故此处是拷贝构造,指向的对象引用会是2
    wp<Thread> weak(strong);//获取弱引用
    self->mHoldSelf.clear();//让强引用减一

#if defined(__ANDROID__)
    // 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();//此处就是返回一个ok
            result = (self->mStatus == OK);

            if (result && !self->exitPending()) {
                result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。
			//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法
            }
        } else {
            result = self->threadLoop();//此处函数是虚函数,需要类去继承。调用的是子类的threadLooper函数。
			//在此处是struct ALooper::LooperThread : public Thread类的threadLoop方法
        }

        // establish a scope for mLock
        {
        Mutex::Autolock _l(self->mLock);
        if (result == false || self->mExitPending) {//一般result都是true,self->mExitPending默认是false,
		//表示是否退出,在requestExit函数和requestExitAndWait函数中会设置为true
            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
            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();//mThreadExitedCondition是Condition类对象。
			//底层调用了pthread_cond_broadcast,唤醒所有在此conditon等待的线程
            break;
        }
        }

        // Release our strong reference, to let a chance to the thread
        // to die a peaceful death.
        strong.clear();//短暂的让强指针引用-1,以便有机会让线程释放。
        // And immediately, re-acquire a strong reference for the next loop
        strong = weak.promote();//立即获取强引用
    } while(strong != nullptr);//死循环

    return 0;
}

2.10 ALooper::post

主要作用为:

1.将消息根据时延大小放到消息队列的指定位置,然后唤醒Alooper线程。

void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);

    int64_t whenUs;
    if (delayUs > 0) {//表示是否延时发送
        int64_t nowUs = GetNowUs();
        whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);

    } else {
        whenUs = GetNowUs();//不延时,获取当前时间
    }

    List<Event>::iterator it = mEventQueue.begin();//此处是遍历消息队列
    while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {//遍历消息队列,按照时延从小到大排序,找到当前消息应该插入的位置。
        ++it;
    }

    Event event;
    event.mWhenUs = whenUs;
    event.mMessage = msg;//生成event

    if (it == mEventQueue.begin()) {//如果当前消息应该插入到消息队列的队首
        mQueueChangedCondition.signal();//则使用条件遍历唤醒线程
    }

    mEventQueue.insert(it, event);//插入该event到指定位置
}

2.11 ALooper::loop

主要作用为:

1.从消息队列中取出消息,然后将消息发送到指定的Ahandler处理者去处理此消息。

bool ALooper::loop() {
    Event event;

    {
        Mutex::Autolock autoLock(mLock);
         if (mThread == NULL && !mRunningLocally) {
             return false;
         }
         if (mEventQueue.empty()) {//此时不为空,不执行
             mQueueChangedCondition.wait(mLock);
             return true;
         }
        int64_t whenUs = (*mEventQueue.begin()).mWhenUs;//获取消息队列的位于头部的event的时延,因为位于头部的event是时延最小的消息
        int64_t nowUs = GetNowUs();

        if (whenUs > nowUs) {//如果时延大于当前时间,意味着时间还没到。
            int64_t delayUs = whenUs - nowUs;
            if (delayUs > INT64_MAX / 1000) {
                delayUs = INT64_MAX / 1000;
            }
            mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);//因为位于头部的event是时延最小的消息,所以此时需要等待时间到达,时间到达后,返回true,然后开启下一次循环

            return true;
        }

        event = *mEventQueue.begin();//取出头部的event事件
        mEventQueue.erase(mEventQueue.begin());//将此evnet从消息队列中删除
    }

    event.mMessage->deliver();//调用Amessage的deliver方法

    // NOTE: It's important to note that at this point our "ALooper" object
    // may no longer exist (its final reference may have gone away while
    // delivering the message). We have made sure, however, that loop()
    // won't be called again.

    return true;
}

2.12 ALooper::createReplyToken

主要作用为:

1.创建一个AReplyToken对象,用于表示是哪个消息需要回复。

sp<AReplyToken> ALooper::createReplyToken() {//此时A线程发送消息,然后阻塞等待B线程发送回复消息。
//然后b线程收到消息后,发送消息到A线程。在这个流程中,AReplyToken在A线程的发送消息的时候被创建,然后保存该回复令牌到发送消息内部。
//当发送的消息到达B线程后,b线程会取出此回复令牌,然后将回复的消息,设置进此AReplyToken对象中,由于A线程也持有此对象,故A线程会死循环的拿回复的消息。
    return new AReplyToken(this);
}

2.13 ALooper::awaitResponse

死循环取回回复,到response中。取回后返回ok,未取回,则一直wait等待阻塞。

status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
    // return status in case we want to handle an interrupted wait
    Mutex::Autolock autoLock(mRepliesLock);
    CHECK(replyToken != NULL);
    while (!replyToken->retrieveReply(response)) {//死循环取回回复,到response中。取回后返回ok,未取回,则一直wait等待阻塞。
        {
            Mutex::Autolock autoLock(mLock);
            if (mThread == NULL) {
                return -ENOENT;
            }
        }
        mRepliesCondition.wait(mRepliesLock);
    }
    return OK;
}

2.14 ALooper::postReply

1.将接收方Ahandler回复的Amessage设置到replyToken对象中。

2.唤醒发送方wait之前wait阻塞的地方。

status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
    Mutex::Autolock autoLock(mRepliesLock);
    status_t err = replyToken->setReply(reply);//将此回复消息reply设置到replyToken中
    if (err == OK) {
        mRepliesCondition.broadcast();//广播之前mRepliesCondition.wait(mRepliesLock)的地方。
    }
    return err;
}

 将Amessage消息保存到AReplyToken类对象中。

status_t AReplyToken::setReply(const sp<AMessage> &reply) {
    if (mReplied) {
        ALOGE("trying to post a duplicate reply");
        return -EBUSY;
    }
    CHECK(mReply == NULL);
    mReply = reply;//将传入的Amessage消息保存到AReplyToken中
    mReplied = true;
    return OK;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】CrossEntropyLoss需要手动softmax吗?

【深度学习】CrossEntropyLoss需要手动softmax吗&#xff1f; 问题&#xff1a;CrossEntropyLoss需要手动softmax吗&#xff1f;答案&#xff1a;不需要官方文档代码解释 问题&#xff1a;CrossEntropyLoss需要手动softmax吗&#xff1f; 之前用 pytorch 实现自己的网络时&…

EtherCAT转ModbusTCP相关技术

EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ftt&id822721028899 MS-GW15 概述 MS-GW15 是 EtherCAT 和 Modbus TCP 协议转换网关&#xff0c;为用户提供一种 PLC 扩展的集成解决方案&#xff0c;可以轻松容易将 Modbu…

使用Centos搭建Rocket.Chat教程

本章教程,主要介绍如何在CentOS系统上搭建Rocket.Cha。 一、Rocket.Chat是什么? Rocket.Chat 是一个开源的团队协作和通讯平台,类似于 Slack 或 Microsoft Teams。它提供了即时消息、视频会议、文件共享、以及与其他服务的集成等功能。用户可以在自己的服务器上部署 Rocket.…

jenkins 构建报错 mvn: command not found

首先安装过 maven&#xff0c;并且配置过环境变量 win r ,输入 cmd 键入 mvn -v 出现上图输出&#xff0c;则证明安装成功。 原因 jenkins 没有 maven 配置全局属性, 导致无法找到 mvn 命令。 解决方案 找到全局属性&#xff0c;点击新增&#xff0c;配置 MAVEN_HOME 路…

C++入门基础知识134—【关于C 库函数 - gmtime()】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 库函数 - gmtime()的相关内容&#xf…

如何开发一个摄影行业小程序?开发一个摄影行业小程序需要哪些功能?南昌各行业小程序开发

如何开发一个摄影行业小程序&#xff1f;开发一个摄影行业小程序需要以下步骤&#xff1a; 1、需求分析&#xff1a;明确小程序的定位和功能需求&#xff0c;例如拍照、修图、分享、预约摄影师等。 2、设计界面&#xff1a;根据需求分析&#xff0c;设计小程序的用户界面&…

虚幻引擎5(UE5)学习教程

虚幻引擎5&#xff08;UE5&#xff09;学习教程 引言 虚幻引擎5&#xff08;Unreal Engine 5&#xff0c;简称UE5&#xff09;是Epic Games开发的一款强大的游戏引擎&#xff0c;广泛应用于游戏开发、影视制作、建筑可视化等多个领域。UE5引入了许多先进的技术&#xff0c;如…

linux线程的认识

1.虚拟地址空间 管理进程的pcb结构体task_struct中有一个mm_struct指针&#xff0c;指向虚拟地址空间&#xff0c;而编译好的代码中有地址&#xff0c;但是是虚拟地址&#xff0c;那么虚拟地址是怎么转化成真实的物理地址呢&#xff1f;通过页表转化 我们知道&#xff0c;代码…

05 Django 框架模型介绍(一)

文章目录 1、Django 模型简介2、Django 中创建并使用模型&#xff08;1&#xff09;新加一个名为 myapp 的应用&#xff08;2&#xff09;定义模型类&#xff08;2&#xff09;激活模型类&#xff08;3&#xff09;创建数据库迁移文件&#xff08;4&#xff09;应用迁移文件 3、…

Autosar CP中的I/O硬件抽象层功能与接口使用导读

规范的主要内容 I/O硬件抽象层&#xff08;I/O Hardware Abstraction Layer&#xff0c;简称IoHwAb&#xff09;的主要功能包括以下几点&#xff1a; 提供硬件访问接口&#xff1a;I/O硬件抽象层为上层软件组件&#xff08;如应用层软件&#xff09;提供访问微控制器硬件&…

【毫米波雷达(三)】汽车控制器启动流程——BootLoader

汽车控制器启动流程——BootLoader 一、什么是Bootloader(BT)&#xff1f;二、FBL、PBL、SBL、ESS的区别三、MCU的 A/B分区的实现 一、什么是Bootloader(BT)&#xff1f; BT就是一段程序&#xff0c;一段引导程序。它包含了启动代码、中断、主程序等。 雷达启动需要由BT跳转到…

初始JavaEE篇——多线程(8):JUC的组件

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 目录 Callable接口 ReentrantLock synchronized 与 ReentrantLock的区别 信号量&#xff08;Semaphore&#xff09; CountDown…

Vue3+Data-V实现可视化大屏页面布局

目录 一、前言 二、环境准备 1.Vue3安装npm create vuelatest 2.Data-V配置 项目Data-v安装 main.js中注册Data-v到全局 ​编辑可使用按需引入 3.测试 三、导航栏路由跳转配置 1.子组件mainNav组件准备 2.父组件准备导航栏参数传递 3.子组件接收父组件参数 4.导航…

Solana 代币 2022 — Transfer Hook

从零到英雄的 Solana 代币 2022 — Transfer Hook Token 2022 计划引入了几项令人兴奋的扩展&#xff0c;增强了铸造和代币账户的功能。在这些功能中&#xff0c;我个人最喜欢的是Transfer Hook &#xff08;转账钩子&#xff09; 。 想象时间 让我们戴上想象的帽子&#xf…

Edge浏览器设置优化

依次点击右上角的三个点-“设置”。 在“外观”设置项中&#xff0c;关闭“显示选项卡操作菜单”、“在垂直选项卡中隐藏标题栏”、“在标题栏中显示个人资料图标”&#xff0c;选择“不显示独立搜索框”。 在“选择要在工具栏上显示的按钮”&#xff0c;开启“下载按钮”。 重…

电脑软件:推荐一款免费且实用的电脑开关机小工具

目录 一、软件简介 二、软件功能 三、软件特点 四、使用说明 五、软件下载 今天给大家推荐一款免费且实用的电脑开关机小工具KShutdown&#xff0c;有需要的朋友可以下载试一下&#xff01; 一、软件简介 KShutdown是一款精巧且实用的定时自动关机小工具&#xff0c;对于…

Python Matplotlib 子图绘制

Python 中的子图绘制 在数据可视化中&#xff0c;展示多个图表在同一个画布上是常见的需求&#xff0c;这样可以更直观地比较不同数据集之间的关系。Python 中的 Matplotlib 库为我们提供了强大的功能来实现这一点。在本篇文章中&#xff0c;我们将详细介绍如何使用 Matplotli…

透明加密技术是什么?透明加密技术的原理与应用实践(内含代表性软件分享)

触目惊心&#xff01;10大典型间谍案例回顾 张某离职前搜集大量文件资料&#xff0c;甚至拆开电脑主机拷贝文件 私自存有5200份文件资料 其中标注绝密级的59份 机密级848份 秘密级541份 在当今这个信息化高速发展的时代&#xff0c;透明加密技术已不容忽视。那么&#xff…

rhce:web服务器

web服务器简介 服务器端&#xff1a;此处使用 nginx 提供 web 服务&#xff0c; RPM 包获取&#xff1a; http://nginx.org/packages/ /etc/nginx/ ├── conf.d #子配置文件目录 ├── default.d ├── fastcgi.conf ├── fastcgi.conf.default ├── fastcgi_params #用…

后端:Spring、Spring Boot-实例化Bean依赖注入(DI)

文章目录 1. 实例化Bean2. 使用FactoryBean3. 依赖注入(DI)3.1 AutoWired 属性注入(查找顺序&#xff1a;先类型&#xff0c;后名字)3.2 AutoWired 在构造函数&参数上的使用3.3 Inject和Resource 进行依赖注入3.4 Value 进行注入 1. 实例化Bean 默认使用无参构造函数&…