epoll監聽文件_介紹一下 Android Handler 中的 epoll 機制?

介紹一下 Android Handler 中的 epoll 機制?

目錄:

  1. IO 多路復用
  2. select、poll、epoll 對比
  3. epoll API
  4. epoll 使用示例
  5. Handler 中的 epoll 源碼分析

IO 多路復用

IO 多路復用是一種同步 IO 模型,實現一個線程可以監視多個文件句柄。一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作,沒有文件句柄就緒時會阻塞應用程序,交出 cpu。

與多進程和多線程技術相比,IO 多路復用技術的最大優勢是系統開銷小,系統不必為每個 IO 操作都創建進程或線程,也不必維護這些進程或線程,從而大大減小了系統的開銷。

select、poll、epoll 就是 IO 多路復用三種實現方式。

select、poll、epoll 對比

select 最大連接數為進程文件描述符上限,一般為 1024;每次調用 select 拷貝 fd;輪詢方式工作時間復雜度為 O(n)

poll 最大連接數無上限;每次調用 poll 拷貝 fd;輪詢方式工作時間復雜度為 O(n)

epoll 最大連接數無上限;首次調用 epoll_ctl 拷貝 fd,調用 epoll_wait 時不拷貝;回調方式工作時間復雜度為 O(1)

epoll API

int?epoll_create(int?size);

創建 eventpoll 對象,并將 eventpoll 對象放到 epfd 對應的 file->private_data 上,返回一個 epfd,即 eventpoll 句柄。

int?epoll_ctl(int?epfd,?int?op,?int?fd,?struct?epoll_event?*event)?//返回值:成功?0;失敗?-1

對一個 epfd 進行操作。op 表示要執行的操作,包括 EPOLL_CTL_ADD (添加)、EPOLL_CTL_DEL (刪除)、EPOLL_CTL_MOD (修改);fd 表示被監聽的文件描述符;event 表示要被監聽的事件,包括:

  • EPOLLIN(表示被監聽的fd有可以讀的數據)
  • EPOLLOUT(表示被監聽的fd有可以寫的數據)
  • EPOLLPRI(表示有可讀的緊急數據)
  • EPOLLERR(對應的fd發生異常)
  • EPOLLHUP(對應的fd被掛斷)
  • EPOLLET(設置EPOLL為邊緣觸發)
  • EPOLLONESHOT(只監聽一次)
int?epoll_wait(int?epfd,?struct?epoll_event?*events,?int?maxevents,?int?timeout)?//返回值:監聽到的產生的事件數

等待 epfd 監聽的 fd 所產生對應的事件。epfd 表示 epoll句柄;events 表示回傳處理事件的數組;maxevents 表示每次能處理的最大事件數;timeout:等待 IO 的超時時間,-1 表示一直阻塞直到來 IO 被喚醒,大于 0 表示阻塞指定的時間后被喚醒

epoll 使用示例

創建一個管道,使用 epoll 監聽管道讀端,然后進入阻塞:

?int?pipFd[2];
?pipe(pipFd);?//打開管道

?struct?epoll_event?event;
?event.data.fd?=?pipFd[0];?//設置為監聽管道讀端
?event.events?=?EPOLLIN?|?EPOLLET;?//設置參數,接收可以?read()?的通知

?int?epfd?=?epoll_create(256);?//創建?epoll?對象
?int?res?=?epoll_ctl(epfd,?EPOLL_CTL_ADD,?pipFd[0],?&event);?//添加管道讀端為要監聽的文件描述符

?struct?epoll_event?allEvs[256];
?int?count?=?epoll_wait(epfd,?allEvs,?256,?5000);?//當前線程進入阻塞,等待被喚醒
?for(int?i?=?0;?i?//被喚醒,處理觸發喚醒文件描述符
?????if(allEvs[i].data.fd?==?pipFd[0]?&&?(allEvs[i].events?&?EPOLLIN)){
?????????char?buffer[256];
?????????read(pipeFd,?buffer,?100);?//接收到管道可以進行讀的信號,開始讀取
?????}
?}

在其他線程寫入管道,通知喚醒:

?write(pipFd[1],?str,strlen("hello"));

eventfd

eventfd 是 Linux 系統中一個用來通知事件的文件描述符,基于內核向用戶空間應用發送通知的機制,可以有效地被用來實現用戶空間事件驅動的應用程序。

簡而言之:eventfd 就是用來觸發事件通知,它只有一個系統調用接口:

int?eventfd(unsigned?int?initval,?int?flags);

表示打開一個 eventfd 文件并返回文件描述符,支持 epoll/poll/select 操作。

之所以要在介紹 Handler native 源碼前先介紹 eventfd,是因為在 Android 6.0 后,Handler 底層替換為 eventfd/epoll 實現。而 6.0 之前是由 pipe/epoll 實現的,就像上面的 epoll 使用示例那樣。

Handler 中的 epoll 源碼分析

主要分析 MessageQueue.java 中的三個 native 函數:

private?native?static?long?nativeInit();?//返回?ptr
private?native?void?nativePollOnce(long?ptr,?int?timeoutMillis);?//阻塞
private?native?static?void?nativeWake(long?ptr);?//喚醒
nativeInit

首先來看 nativeInit 方法,nativeInit 在 MessageQueue 構造函數中被調用,其返回了一個底層對象的指針:

????MessageQueue(boolean?quitAllowed)?{
????????mQuitAllowed?=?quitAllowed;
????????mPtr?=?nativeInit();
????}

對應實現在 android_os_MessageQueue.cpp 中:

static?jlong?android_os_MessageQueue_nativeInit(JNIEnv*?env,?jclass?clazz)?{
????NativeMessageQueue*?nativeMessageQueue?=?new?NativeMessageQueue();
????...
????return?reinterpret_cast(nativeMessageQueue);
}

可見 MessageQueue 對應的底層對象就是 NativeMessageQueue,而 NativeMessageQueue 初始化時會創建一個底層的 Looper 對象:

NativeMessageQueue::NativeMessageQueue()?:
????????mPollEnv(NULL),?mPollObj(NULL),?mExceptionObj(NULL)?{
????mLooper?=?Looper::getForThread();
????if?(mLooper?==?NULL)?{
????????mLooper?=?new?Looper(false);
????????Looper::setForThread(mLooper);
????}
}

如上代碼,可以知道 Looper 對象是 ThreadLocal 類型。Looper 的構造函數如下:

Looper::Looper(bool?allowNonCallbacks)?:
????????mAllowNonCallbacks(allowNonCallbacks),?...{
????mWakeEventFd?=?eventfd(0,?EFD_NONBLOCK?|?EFD_CLOEXEC);
????...
????rebuildEpollLocked();
}

首先通過 eventfd 系統調用返回一個文件描述符,專門用于事件通知。接著來看 rebuildEpollLocked 方法:

void?Looper::rebuildEpollLocked()?{
????mEpollFd?=?epoll_create(EPOLL_SIZE_HINT);
????struct?epoll_event?eventItem;
????memset(&?eventItem,?0,?sizeof(epoll_event));
????eventItem.events?=?EPOLLIN;
????eventItem.data.fd?=?mWakeEventFd;
????int?result?=?epoll_ctl(mEpollFd,?EPOLL_CTL_ADD,?mWakeEventFd,?&?eventItem);?
????...
}

可以看到我們已經熟悉的 epoll 操作了:通過 epoll_create 創建 epoll 對象,然后調用 epoll_ctl 添加 mWakeEventFd 為要監聽的文件描述符。

nativePollOnce

之前學習 Handler 機制時多次看到過 nativePollOnce 方法,也知道它會進入休眠,下面就來徹底搞懂它的原理。對應的底層調用同樣是在 android_os_MessageQueue.cpp 中:

static?void?android_os_MessageQueue_nativePollOnce(JNIEnv*?env,?jobject?obj,
????????jlong?ptr,?jint?timeoutMillis)?{
????NativeMessageQueue*?nativeMessageQueue?=?reinterpret_cast(ptr);
????nativeMessageQueue->pollOnce(env,?obj,?timeoutMillis);
}void?NativeMessageQueue::pollOnce(JNIEnv*?env,?jobject?pollObj,?int?timeoutMillis)?{
????mLooper->pollOnce(timeoutMillis);
????...
}

可以看到實現同樣是在 Looper.cpp 中,接著來看 Looper 的 pollOnce 方法:

int?Looper::pollOnce(int?timeoutMillis,?int*?outFd,?int*?outEvents,?void**?outData)?{
????for?(;;)?{
????????...
????????result?=?pollInner(timeoutMillis);
????}
}

int?Looper::pollInner(int?timeoutMillis)?{
????...
????struct?epoll_event?eventItems[EPOLL_MAX_EVENTS];
????int?eventCount?=?epoll_wait(mEpollFd,?eventItems,?EPOLL_MAX_EVENTS,?timeoutMillis);
????...

至此通過調用 epoll_wait 方法,當前線程進入休眠,等待被喚醒。

nativeWake

最后來看如何通過 nativeWake 喚醒線程,首先是 android_os_MessageQueue.cpp 中:

static?void?android_os_MessageQueue_nativeWake(JNIEnv*?env,?jclass?clazz,?jlong?ptr)?{
????NativeMessageQueue*?nativeMessageQueue?=?reinterpret_cast(ptr);
????nativeMessageQueue->wake();
}void?NativeMessageQueue::wake()?{
????mLooper->wake();
}

與 nativeInit、nativePollOnce 一樣,最終實現都是在 Looper.cpp 中,Looper 的 wake 方法如下:

void?Looper::wake()?{
????uint64_t?inc?=?1;
????ssize_t?nWrite?=?TEMP_FAILURE_RETRY(write(mWakeEventFd,?&inc,?sizeof(uint64_t)));
????if?(nWrite?!=?sizeof(uint64_t))?{
????????if?(errno?!=?EAGAIN)?{
????????????LOG_ALWAYS_FATAL("Could?not?write?wake?signal?to?fd?%d:?%s",
????????????????????mWakeEventFd,?strerror(errno));
????????}
????}
}

其中關鍵邏輯是對 mWakeEventFd 發起寫入操作,從而喚醒 nativePollOnce 中通過 epoll_wait 進入休眠的線程。

推薦閱讀:

開源一組視頻時間軸控件

Activity Window 創建及添加過程

抽象工廠模式

Android UI 繪制請求與繪制時機工廠模式Android 消息屏障與異步消息Java 并發編程知識點梳理總結1638a8c94cb8f3ab6485ce19f5c312e8.png

關注我

助你升職加薪

Android?面試官

7c2fe87486f6f45d523db409a1fa27c3.png464f1a7947a055925b4fabc089f94f6a.png點贊在看,?年薪百萬

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275975.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275975.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275975.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端工程師的一大神器——puppeteer

大家好,我是若川。歡迎加我微信 ruochuan12,長期交流學習。今天推薦神器puppeteer,我猜有挺多人不知道。文章不長,看完有空也可以試玩。我18年也寫過一篇puppeteer爬取生成pdf的文章,時間真快。前端使用puppeteer 爬蟲…

selenium界面元素定位

一、 Selenium界面元素定位 本文元素定位以das2為例 #導入包 from selenium import webdriver #打開火狐驅動 driverwebdriver.Firefox() #訪問網址 driver.get("http://192.168.3.217:8080/das/seatlogin.jsp ") 進行web頁面自動化測試,對頁面上…

vue.js ui_UI / UX開發:考慮Vue.js

vue.js uiBecause sometimes we have to add logic to our concepts, and Vue makes it a whole lot easier.因為有時我們必須在概念中添加邏輯,而Vue使其變得更加容易。 FULL DISCLOSURE: THIS IS NOT A COMPLETE JAVASCRIPT OR VUE COURSE. There’s no way I co…

Silverlight學習筆記十七BingMap(三)之地圖的地區標識

如果我們需要在Bing Maps中加入一個小圖釘標記&#xff0c;該如何實現了&#xff1f; Bing Maps控件已經為我們提供了這個功能&#xff0c;在Microsoft.Maps.MapControl名稱空間下提供了實現圖釘應用的圖釘層Pushpin類用該類來實現普通標識 在Xaml中添加<map:Pushpin Locati…

win10查看pcie設備_壹拓網科技解密WIN10系統使用向日葵開機棒遠程開機需要設置幾個地方...

向日葵開機棒&#xff0c;是一款非常好用的遠程智能遠程開機硬件&#xff0c;它一頭接網線&#xff0c;另外一頭和被開電腦接在同一個路由器下&#xff0c;不需要和被開電腦或者設備直接連接&#xff0c;當然&#xff0c;被開電腦需要有線聯網&#xff0c;暫時不支持使用無線方…

如何成為公司獨當一面的工程師

大家好&#xff0c;我是若川。歡迎加我微信 ruochuan12&#xff0c;長期交流學習。今天推薦黃老師的這篇文章&#xff0c;你可能看到過了&#xff0c;但值得再看一遍。之前常有小伙伴問&#xff0c;大多情況下我都會分享這篇文章。點擊下方卡片關注我、加個星標&#xff0c;或者…

webpack4.0配置記錄(2)

接上一篇webpack4.0配置記錄(1),繼續記錄學習webpack配置。 定義環境變量 new Webpack.DefinePlugin({//用來定義全局環境變量DEV:JSON.stringify(dev),FLAG:true }), webpack簡單優化 noParsemodule:{noParse:/jquery/,//不去解析設置的包所依賴的關系,如jquery } ignorePlugi…

flex如何做響應式設計_響應式設計-您做錯了!

flex如何做響應式設計Responsive design is not just about the web that automatically adjusts to different screen resolutions and resizeable images, but designs that are crucial for web performance.自適應設計不僅涉及可自動適應不同屏幕分辨率和可調整大小圖像的網…

怎么查看和獲取SQL Server實例名

查看實例名時可用 1、服務—SQL Server(實例名)&#xff0c;默認實例為(MSSQLSERVER) 或在連接企業管理時-查看本地實例 2、通過注冊表 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft SQL Server/InstalledInstance 3、用命令 sqlcmd/osql sqlcmd -L sqlcmd -Lc osql -L 獲…

30萬手表推薦_今年六十歲生日,兒子說要送只30萬的手表,請問有哪些推薦?...

關注腕表部落&#xff0c;盡享腕表生活一位讀者向筆者提出這樣一個問題&#xff1a;今年六十歲生日&#xff0c;兒子說要送只30萬的手表&#xff0c;請問有哪些推薦&#xff1f;首先要恭喜這位老爺子&#xff0c;一來是生日馬上就要到了&#xff0c;二來是還有這么孝順而且慷慨…

關注博客

https://blog.51cto.com/oldboyhttps://blog.51cto.com/yw666轉載于:https://blog.51cto.com/11732716/2348556

寫 Node.js 代碼,從學會調試開始

大家好&#xff0c;我是若川&#xff08;點這里加我微信 ruochuan12&#xff0c;長期交流學習&#xff09;。今天推薦這篇調試文章&#xff0c;熟悉我的讀者都知道我寫的源碼文章都多次強調要調試&#xff0c;而且寫了調試方法。點擊下方卡片關注我、加個星標&#xff0c;或者查…

創建用戶友好的表單

Forms are a common way to engage with users and could be a user’s first impression of your product. Since forms aren’t always the user’s favourite thing, it is essential to make filling out forms as easy as possible. Let’s go over a few tips for creati…

細節決定成敗—關于.net的.dll.refresh文件

一直在做.net的項目&#xff0c;c/s的、b/s的&#xff0c;一直沒有注意這個東西。眾所周知&#xff0c;.net的程序生成后會在bin目錄下生成.dll文件&#xff0c;而.dll.refresh這個文件從何而來呢&#xff1f;那天無聊地google了下才知&#xff0c;這個東東是在你的項目中引用第…

環境在c盤_如何給女朋友解釋為什么 Windows 上面的軟件都把自己安裝在 C 盤

本文經授權轉載自漫畫編程(ID&#xff1a;mhcoding)周末&#xff0c;我在家里面看電視&#xff0c;女朋友正在旁邊鼓搗她的電腦&#xff0c;但是好像并不是很順利&#xff0c;于是就有了以下對話。計算機存儲我們使用的計算機中&#xff0c;保存信息的介質有兩類&#xff1a;一…

能讓你縱享絲滑的SSR技術,轉轉這樣實踐

大家好&#xff0c;我是若川&#xff08;點這里加我微信 ruochuan12&#xff0c;長期交流學習&#xff09;。今天推薦這篇圖文并茂的SSR技術文章。這是江西前端群里一個小伙伴的文章。群里小伙伴很多都在知名大廠&#xff0c;但他們都很低調。點擊下方卡片關注我、加個星標&…

魅族魅藍mirror簡單打開usb調試模式的步驟

經常我們使用安卓手機鏈接電腦的時候&#xff0c;或者使用的有些應用比如我們企業營銷團隊經常使用的應用引號精靈&#xff0c;以前使用的老版本就需要開啟USB調試模式下使用&#xff0c;現經常新版本不需要了&#xff0c;如果手機沒有開啟USB調試模式&#xff0c;電腦則無辦法…

hp-ux 單用戶 啟動_UX備忘單:搜索與瀏覽

hp-ux 單用戶 啟動重點 (Top highlight)When designing search results and interest sites, you have to keep in mind what ‘mode’ your user is in. Are they in ‘searching mode’ or ‘browsing mode’? This will help you determine how to design your platform to…

細數開源歷史上的九個重大事件

開放源碼&#xff08;開源&#xff09;的精神在于使用者可以使用、復制、散布、研究和改進軟件。這可以追溯到20世紀60年代&#xff0c;至今已有半個世紀了。伯樂在線-職場博客的這篇文章將列舉開源歷史上的九大重要事件。雖然本文不是專門對開源產品&#xff0c;但還是說到了一…

有贊大數據平臺安全建設實踐

一、概述 在大數據平臺建設初期&#xff0c;安全也許并不是被重點關注的一環。大數據平臺的定位主要是服務數據開發人員&#xff0c;提高數據開發效率&#xff0c;提供便捷的開發流程&#xff0c;有效支持數倉建設。大數據平臺的用戶都是公司內部人員。數據本身的安全性已經由公…