`

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:

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



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

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


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

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

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


 这样,它们就通过LooperpollOnce实现了在Looper中的管道上的读端上的睡眠等待。

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


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


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

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

 
本文节选自《深入剖析Android系统》一书

杨长刚

电子工业出版社出版

 

  • 大小: 28.1 KB
  • 大小: 3 KB
  • 大小: 10.3 KB
  • 大小: 8.3 KB
  • 大小: 6.7 KB
  • 大小: 6.7 KB
  • 大小: 4.8 KB
  • 大小: 2.3 KB
  • 大小: 18.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics