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函數去喚醒睡眠等待。