zoukankan      html  css  js  c++  java
  • Looper中的睡眠等待与唤醒机制

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

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

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

     

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

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

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

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

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

     

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

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

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

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

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

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

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

    杨长刚著

    电子工业出版社出版

  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    An existing connection was forcibly closed by the remote host
    各种浏览器的兼容css
    vs输出窗口,显示build的时间
    sass
    网站设置404错误页
    List of content management systems
    css footer not displaying at the bottom of the page
    强制刷新css
    sp_executesql invalid object name
  • 原文地址:https://www.cnblogs.com/broadview/p/2881284.html
Copyright © 2011-2022 走看看