Looper中的睡眠等待与唤醒机制

Looper中的睡眠等待与唤醒机制

C++Looper中的睡眠和唤醒机制是通过pollOncewake函数提供的,它们又是利用操作系统(Linux内核)的epoll机制来完成的。当被监控的文件(通过epoll_ctlEPOLL_CTL_ADD添加进去)可I/O时,epoll_wait调用会从睡眠中醒来,这时,可以检查是哪个(或哪些)文件描述符对应的文件可以进行I/O读写了,从而做出进一步处理。使用者利用它们就可以拥有睡眠等待和唤醒机制。下面详述。

Looper的构造函数中,会创建一个管道(下面的行73),然后调用epoll_create获取一个epoll的实例的描述符(行88),最后将管道读端描述符作为一个事件报告项添加给epoll(行95)。这样,当管道读端有数据可读时,将会得到报告。Looper的构造函数如下(见文件Looper.cpp:

Looper中的睡眠等待与唤醒机制_第1张图片

LooperpollOnce函数将最终调用到其pollInner函数。在后者里面,将调用epoll_wait睡眠等待其监控的文件描述符是否有可I/O事件的到来,若有(哪怕只有一个),epoll_wait将会醒来,然后可检查是哪个文件描述符上的可I/O事件。pollInner函数中的相关代码如下(见文件Looper.cpp:


Looper中的睡眠等待与唤醒机制_第2张图片
可见,在线程循环中调用了LooperpollOnce函数,将导致睡眠等待在上面的行218处的epoll_wait上。当向消息队列发送消息并进行唤醒时,行218将被唤醒,因此从pollOnce函数中返回,可以从消息队列中取出消息进行处理。

Looper中的睡眠等待与唤醒机制_第3张图片

Looperwake函数用于向管道中写入字符(下面的行367),以唤醒pollOnce


下面来看一下Java层的MessageQueue如何利用这种机制。

前面提到在android.os.MessageQueuenext函数中取出下一个消息时,会调用到native层实现的函数nativePollOnce时,实际调用到了如下native实现(见文件android_os_MessageQueue.cpp):


上面行157pollOnce函数代码是(见文件android_os_MessageQueue.cpp):

Looper中的睡眠等待与唤醒机制_第4张图片
这样,它们就通过LooperpollOnce实现了在Looper中的管道上的读端上的睡眠等待。

android.os.MessageQueueenqueueMessage函数往队列上添加了一个新消息或removeSyncBarrier移除了同步屏障后,可能需要调用nativeWake唤醒,其native实现为:(见文件android_os_MessageQueue.cpp):


上面的行162调用的又是下面的函数,代码如下(见文件android_os_MessageQueue.cpp):


这样,Looper将向管道写端写入字符,唤醒其在管道读端上的睡眠等待。

因此,通过借助于LooperwakepollOnce函数,可以让别的消息队列(如Java层的消息队列)拥有睡眠唤醒机制:没有消息时pollOnce调用者将睡眠等待,有消息时让wake函数去唤醒睡眠等待。

Looper中的睡眠等待与唤醒机制_第5张图片
本文节选自《深入剖析Android系统》一书

杨长刚

电子工业出版社出版

你可能感兴趣的:(移动开发)