Android Handler消息機制底層實現

Handler與Looper、MessageQueue共同實現了線程間消息傳遞。MessageQueue的底層實現是利用管道和epoll機制來實現的。

概括:當我們查看Looper.loop()方法時,會發現其中有一個無線循環。那么這其中的原因又是啥呢。當調用Looper.prepare()方法時,底層會創建一個管道,另外還會創建一個epoll實例去監聽管道的讀文件描述符。

當執行loop方法時,會調用epoll_wait去監聽epoll實例中所監聽的文件描述符有沒有對應的事件,如果沒有的話,該方法就會堵塞,所有for循環就沒有無限執行下去。當有其他線程向handler發送數據時,就會向管道寫數據,那么epoll_wait方法堵塞就會喚醒。

然后我們把管道中的數據都讀出來。下一次進行for循壞的時候又會調用epoll_wait方法,如果消息隊列沒有消息時,就又會堵塞了。

一:什么是管道

管道是一種把兩個進程之間的標準輸入和標準輸出連接起來的機制,從而提供一種讓多個進程間通信的方法。通俗一點說就是一個進程向管道寫入數據,另外一個進程可以從管道中讀取該數據。(ps:不只進程,線程當然也是可以的)

當進程創建管道時,每次都需要提供兩個文件描述符來操作管道。其中一個對管道進行寫操作,另一個對管道進行讀操作。

  1. 使用pipe函數創建一個管道
int pipefd[2];
pipe(pipefd);

當創建管道成功后,pipefd數組將會被賦值,其中pipefd[0]為管道的讀端文件描述符,pipedf[1]為管道的寫端文件描述符。

  1. 使用pipe函數創建是匿名管道,管道是沒有名字的,可以使用那倆個文件描述符對管道進行讀寫操作。

  2. 寫管道操作默認是堵塞的,也就是把數據全部寫入緩存后write函數才返回,如果緩存滿了就一直堵塞,直到緩存里的數據被讀出,數據被全部寫入。

二. epoll機制

epoll機制:可以同時監聽多個文件描述符的IO讀寫事件而設計的。

1. 創建一個epoll實例
int epfd = epoll_create(intsize);  

參數 initsize 為epoll實例需要監聽的IO讀寫事件的數目大小。epfd 為epoll實例的文件描述符。

2. 使用epoll來監聽某個文件描述符上的事件
int epoll_ctl(int epfd, intop, int fd, struct epoll_event* event); 

第一個參數是 epoll_create() 的返回值,
第二個參數 op 表示動作,用三個宏來表示:
EPOLL_CTL_ADD: 注冊新的fd到epfd中;
EPOLL_CTL_MOD: 修改已經注冊的fd的監聽事件;
EPOLL_CTL_DEL: 從epfd中刪除一個fd;
第三個參數是需要監聽的fd,
第四個參數是告訴內核需要監聽什么事件

舉例:利用epoll來監聽管道的讀文件描述符
int pipefd[2];
pipe(pipefd);  //創建管道

int epfd = epoll_create(intsize); //創建epoll 
struct epoll_event eventItem;
memset(& eventItem,0,sizeof(epoll_event)); // 給eventItem分配內存
eventItem.events = EPOLLIN; //EPOLLIN  表示對應的文件描述符上有可讀數據
eventItem.data.fd = pipefd[0];
result = epoll_ctl(epfd,EPOLL_CTL_ADD,pipefd[0],&eventItem);

分析: EventItem是我們定義的事件,事件的類型為EPOLLIN。表示事件為對應的文件描述符上有可讀數據,eventItem.data.fd 指定了特定文件描述符。調用epoll_ctl 去監聽管道讀文件描述符上是否有流到達

3. 使用epoll_wait 來監聽注冊在epoll實例中的文件描述符的IO讀寫事件

epoll實例可以注冊多個文件描述符,epoll_wait監聽epoll實例,這正是多路復用機制,一個epoll監聽了多個IO事件。

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
  • 參數events用來從內核得到事件的集合
  • maxevents告之內核這個events有多大(數組成員的個數),這個maxevents的值不能大于創建epoll_create()時的size
  • 參數timeout是超時時間(毫秒,0會立即返回,-1永久等待)
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd,eventItems,EPOLL_MAX_EVENTS,timeoutMillis)

我們接著利用前面epoll_ctl 注冊管道的讀文件描述符。這里我們對epoll實例進行監聽等待。當管道的讀文件描述符沒有數據時,這里會被阻塞。當有其他線程或者進程向管道寫文件描述符寫入數據時,這時epoll_wait會將數據放入eventItems數組中,通過遍歷,我們可以拿到對應的事件。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容