前言
我做了兩期有關(guān)Looper的視頻嚷节,目前來看播放量還不錯硬萍,有興趣的可以去B站觀看扩所,視頻中我提到Looper采用pipe機制wake,糾正一下自己的錯誤朴乖,新版本的Looper已經(jīng)采用eventfd代替pipe祖屏。
一、Android 5.1或更早版本
//初始化
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
int wakeFds[2];
int result = pipe(wakeFds);//創(chuàng)建一個pipe
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
....
//epoll 監(jiān)聽pipe的讀端mWakeReadPipeFd
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
}
void Looper::wake() {
ssize_t nWrite;
do {
//wake的時候往pipe的寫端mWakeWritePipeFd寫一字符"W"
nWrite = write(mWakeWritePipeFd, "W", 1);
} while (nWrite == -1 && errno == EINTR);
if (nWrite != 1) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
第一步:初始化創(chuàng)建pipe买羞,產(chǎn)生2個fd袁勺,分別是mWakeReadPipeFd和mWakeWritePipeFd
第二步:epoll機制監(jiān)聽pipe的讀端mWakeReadPipeFd
第三步:wake的時候往pipe的寫端mWakeWritePipeFd,寫入一個字符w就可以喚醒Looper
二畜普、Android 6.0或更高的版本
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
mWakeEventFd = eventfd(0, EFD_NONBLOCK);//用eventfd初始化mWakeEventFd
AutoMutex _l(mLock);
rebuildEpollLocked();
}
void Looper::rebuildEpollLocked() {
...
//用epoll機制監(jiān)聽mWakeEventFd
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
...
}
void Looper::wake() {
uint64_t inc = 1;
//直接write一個1到mWakeEventFd喚醒
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
第一步:eventfd初始化mWakeEventFd
第二步:epoll機制監(jiān)聽eventfd的mWakeEventFd
第三步:wake的時候往mWakeEventFd期丰,寫入一個數(shù)字1就可以喚醒Looper
三、為什么用eventfd代替pipe
3.1 fd減少一個
每個進程fd是有上限的吃挑,一般是1024個钝荡,超出了就是OOM
pipe產(chǎn)生2個fd
eventfd只會產(chǎn)生1個fd
3.2 輕量化
雖然wake的時候都是往fd寫入一個字符或者數(shù)字,但是內(nèi)核中pipe和eventfd對write的系統(tǒng)調(diào)用的實現(xiàn)可不同儒鹿,可以觀看我的視頻化撕,了解詳情。
pipe需要維護一個內(nèi)存緩沖區(qū)约炎,一般是4096B
eventfd只需要維護一個無符號的64位整形計數(shù)器 counte
四植阴、總結(jié)
很明顯eventfd用更少的代價達到了相同的目的蟹瘾,所以Android官方果斷就換了,很多舊書上可能還是介紹用pipe掠手,這里需要注意一下憾朴,但是你只要理解Looper設(shè)計的精髓,這些升級對你來說喷鸽,看一下源碼就知道了众雷。