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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索NetCat:网络流量监测与数据传输的利器

从简单的数据传输到复杂的网络调试&#xff0c;NetCat的灵活性和多功能性让人赞叹不已&#xff0c;在这篇文章中我将深入探讨NetCat的魅力&#xff0c;揭示它的基本功能、实用技巧以及在日常工作中的应用场景&#xff0c;发现如何用这一小工具提升的网络技能与效率。 目录 Net…

UE4安卓Gradle工程中的libUE4.so的生成原理

流程图 流程图放在最前面&#xff0c;下面是讲解。 libUE4.so 问&#xff1a;在UE4安卓开发中&#xff0c;libUE4.so即是符号表&#xff0c;又是引擎代码native&#xff0c;是吗&#xff1f; 答&#xff1a;是的&#xff0c;libUE4.so在UE4安卓开发中既包含符号表&#xff0c;…

wireshark抓包查看langchain的ChatOpenAI接口发送和接收的数据

1. 引入 当我们用vllm部署一个大模型&#xff0c;就可以调用langchain的ChatOpenAI()接口来访问大模型&#xff08;具体过程参考[1]&#xff09;&#xff0c;这也是langchain的Agent的基础接口使用方式。 那么问题来了&#xff0c;这个接口是使用哪种方式与大模型进行通信的呢…

ubuntu 24.04中安装 Easyconnect,并解决版本与服务器不匹配问题

下载安装包 下载地址 https://software.openkylin.top/openkylin/yangtze/pool/all/ 页面搜索 easyconnect 选择 easyconnect_7.6.7.3.0_amd64.deb安装 sudo dpkg --install easyconnect_7.6.7.3.0_amd64.deb卸载 sudo dpkg --remove easyconnect出现的问题 安装以后第…

arcgis坐标系问题

2000数据框的工程只能打开2000坐标系的矢量数据和栅格数据&#xff08;影像图&#xff09;&#xff0c;如果打开80的数据则会投影错误&#xff0c;出现较大偏差。 解决方案&#xff1a;80数据框打开80数据&#xff0c;2000数据库打开2000数据。

0-1规划的求解

实验类型&#xff1a;◆验证性实验 ◇综合性实验 ◇设计性实验 实验目的&#xff1a;学会使用Matlab编程实现求解0-1规划。 实验内容&#xff1a;1.学习使用Matlab定义子函数的命令function&#xff1b; 2.编程求解0-1型整数规划的枚举法或隐枚举法。 例1&#xff1a;求…

RNN与Self-Attention

文章目录 1. SimpleRNN1.1 h t h_t ht​计算1.2 激活函数 2. SimpleRNNSelf-Attention2.1 状态更新2.2 权重 α α α 1. SimpleRNN 学习视频&#xff1a;https://www.youtube.com/watch?vCc4ENs6BHQw&t0s 对于时序数据&#xff0c;输入输出都不固定&#xff0c;需要ma…

R-CNN,Fast R-CNN,

R-CNN R-CNN可以说是利用深度学习进行目标检测的开山之作 RCNN算法流程可分为4个步骤 - 一张图像生成1K~2K个候选区域(使用Selective Search方法) - 对每个候选区域&#xff0c;使用深度网络提取特征 - 特征送入每一类的SVM 分类器&#xff0c;判别是否属于该类 - 使用回归器…

C++/list

目录 1.list的介绍 2.list的使用 2.1list的构造 2.2list iterator的使用 2.3list capacity 2.4list element access 2.5list modifers 2.6list的迭代器失效 3.list的模拟实现 4.list与vector的对比 欢迎 1.list的介绍 list的文档介绍 cplusplus.com/reference/list/li…

人工智能证书合集

本文将对目前市面上主流官方机构颁发的人工智能证书进行整理和介绍&#xff0c;由于整理的证书较多&#xff0c;本文共一万八千多字&#xff0c;请根据自己的考证需求阅读对应部分的内容&#xff0c;希望本文对人工智能行业的从业人员和计划从事人工智能相关岗位工作的人员有所…

TongWeb7.0.E.6_P11嵌入式版本使用指引(by lqw)

文章目录 声明相关概念手册的使用示范工程安装工程介质 安装前准备示范工程参考&#xff08;spring-boot-helloWorld-2.x&#xff09;示范参考 声明 1.本文参考001_TongWeb_V7.0嵌入式版_JavaEE标准容器用户指南_70E6_P11A01.pdf&#xff0c;实际以最新更新的手册为准。 2.本文…

鸿蒙开发融云demo发送图片消息

鸿蒙开发融云demo发送图片消息 融云鸿蒙版是不带UI的&#xff0c;得自己一步步搭建。 这次讲如何发送图片消息&#xff0c;选择图片&#xff0c;显示图片消息。 还是有点难度的&#xff0c;好好看&#xff0c;好好学。 一、思路&#xff1a; 选择图片用&#xff1a;photoVie…

开源OCR免费助力法律文档数字化,提升文档管理效率

一、在法律行业&#xff0c;每天需要处理大量纸质文件&#xff0c;从合同到判决书&#xff0c;手动录入不仅费时&#xff0c;还容易出错。为解决这一问题推出了一款免费开源的OCR智能识别平台&#xff0c;通过先进的光学字符识别&#xff08;OCR&#xff09;技术&#xff0c;将…

详解ReentrantLock--三种加锁方式

目录 介绍AQS: 直观方式解释加锁的流程&#xff1a; Node是什么&#xff1a;它里面有什么属性呢 图解队列的排队过程&#xff1a; 源码分析三种加锁流程&#xff1a; 我们先讲解一下非公平锁的加锁流程&#xff1a; Lock()方式加锁&#xff1a; 在源码里对于Lock()的解…

【教程】Git 标准工作流

目录 前言建仓&#xff0c;拉仓&#xff0c;关联仓库修改代码更新本地仓库&#xff0c;并解决冲突提交代码&#xff0c;合入代码其他常用 Git 工作流删除本地仓库和远程仓库中的文件日志打印commit 相关 前言 Git 是日常开发中常用的版本控制工具&#xff0c;配合代码托管仓库…

Postman断言与依赖接口测试详解!

在接口测试中&#xff0c;断言是不可或缺的一环。它不仅能够自动判断业务逻辑的正确性&#xff0c;还能确保接口的实际功能实现符合预期。Postman作为一款强大的接口测试工具&#xff0c;不仅支持发送HTTP请求和接收响应&#xff0c;还提供了丰富的断言功能&#xff0c;帮助测试…

百度SEO与SEM到底有什么区别?福建企业老板们需要了解的关键点【百度SEO专家】

大家好&#xff0c;我是林汉文&#xff0c;一名百度SEO专家。最近在与一些企业Boss沟通时&#xff0c;我发现很多人对SEO与SEM的区别并不清楚&#xff0c;有时甚至会混为一谈。SEO和SEM确实都是搜索引擎营销的重要手段&#xff0c;但它们在实现方式、效果和适用场景上都有着明显…

JavaFX WebView + Vue初始化加载数据解决方案

一般WebView加载Vue时&#xff0c;我们需要注入一些数据&#xff0c;而我发现当WebView加载完毕再注入脚本&#xff0c;Vue是无法正确识别注入的脚本函数&#xff0c;也无法正确获取所要注入的数据&#xff0c;因此可以采用以下方法解决Vue无法正确加载数据问题 1、配置WebView…

Ubuntu 安装CUDA, cuDNN, TensorRT(草稿)

文章目录 写在前面一、CUDA, cuDNN, TensorRT 三个库的版本的确定二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04, 本文安装的版本&#xff1a; cuda_11.1.0&#xff1b;cuDNN-8.2.1&#xff1b;TensorRT-8.2.4.2 一、CUDA, cuDNN, TensorRT 三个库…

传输层协议TCP详解(上篇)

目录 一. TCP协议 1.1 什么是TCP协议 1.2 TCP为什么叫传输控制协议 二. TCP协议段格式 三. 确认应答&#xff08;ACK&#xff09;机制 3.1 什么是确认应答机制 3.2 推导确认应答机制 四. 超时重传机制 五. 连接管理机制 5.1 六位标志位 5.2 如何…