面試常見(jiàn)問(wèn)題06 - 項(xiàng)目相關(guān)

一. epoll

1. epoll 實(shí)現(xiàn)原理

  • epoll_create:創(chuàng)建一個(gè)epoll對(duì)象,一般 epollfd = epoll_create()
  • epoll_ctl:epoll_add/epoll_del的合體,往epoll對(duì)象中增加/刪除某一個(gè)流的某一個(gè)事件
   epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);  // 注冊(cè)緩沖區(qū)非空事件,即有
                                                        // 數(shù)據(jù)流入
   epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT); // 注冊(cè)緩沖區(qū)非滿事件,即流
                                                        // 可以被寫(xiě)入
  • epoll_wait(epollfd,...):等待直到注冊(cè)的事件發(fā)生
  • 實(shí)現(xiàn)原理
    ??首先,需要調(diào)用epoll_create來(lái)創(chuàng)建一個(gè)epoll的文件描述符,內(nèi)核會(huì)同時(shí)創(chuàng)建一個(gè)eventpoll的數(shù)據(jù)結(jié)構(gòu)。這個(gè)數(shù)據(jù)結(jié)構(gòu)里面會(huì)包含兩個(gè)東西,一個(gè)是紅黑樹(shù),專(zhuān)門(mén)用于存儲(chǔ)epoll_ctl注冊(cè)進(jìn)來(lái)的fd文件描述符;另外一個(gè)是就緒鏈表,用來(lái)存儲(chǔ)epoll_wait調(diào)用相關(guān)的已經(jīng)就緒的fd文件描述符
eventpoll結(jié)構(gòu)體:
struct eventpoll{
   struct rb_root rbr;      // 紅黑樹(shù)的根節(jié)點(diǎn),存儲(chǔ)所有添加到epoll中需要監(jiān)控的事件
   struct list_head rdlist; // 雙鏈表存放將要通過(guò)epoll_wait返回給用戶(hù)的滿足條件的事件
};

??其次,執(zhí)行epoll_ctl時(shí),如果增加socket句柄,則檢查在紅黑樹(shù)中是否存在,存在立即返回,不存在則添加到樹(shù)干上,然后向內(nèi)核注冊(cè)回調(diào)函數(shù),用于當(dāng)中斷事件來(lái)臨時(shí)向準(zhǔn)備就緒鏈表中插入數(shù)據(jù),因?yàn)閑poll中的所有事件,都與網(wǎng)卡驅(qū)動(dòng)程序建立回調(diào)關(guān)系,當(dāng)相應(yīng)的事件發(fā)生的時(shí)候,會(huì)通過(guò)這個(gè)事件的回調(diào)函數(shù),將發(fā)生的事件添加到就緒鏈表當(dāng)中,在epoll中,對(duì)于每一個(gè)事件,都會(huì)建立一個(gè)epitem結(jié)構(gòu)體,如下所示:

struct epitem{
    struct rb_node rbn;        //紅黑樹(shù)節(jié)點(diǎn)
    struct list_head rdllink;  //雙向鏈表節(jié)點(diǎn)
    struct epoll_filefd ffd;   //事件句柄信息
    struct eventpoll* ep;      //指向其所屬的eventpoll對(duì)象
    struct epoll_event event;  //期待發(fā)生的事件類(lèi)型
}

??最后,當(dāng)調(diào)用epoll_wait檢查是否有事件發(fā)生時(shí),只需要檢查eventpoll對(duì)象中的rdlist雙鏈表中是否有需要處理的事件。如果rdlist不為空,則把發(fā)生的事件復(fù)制到用戶(hù)態(tài),同時(shí)將事件數(shù)量返回給用戶(hù)

2. epoll 技術(shù)優(yōu)勢(shì)

  • 支持一個(gè)進(jìn)程打開(kāi)大數(shù)目的socket描述符(FD)
  • IO效率不隨FD數(shù)目增加而線性下降
  • 使用mmap加速內(nèi)核與用戶(hù)空間的消息傳遞,通過(guò)內(nèi)核與用戶(hù)空間mmap同一塊內(nèi)存

3. epoll 的 select 與 poll 的區(qū)別

  • select 與 poll 使用輪詢(xún)方式掃描文件描述符,單個(gè)進(jìn)程監(jiān)控的數(shù)量有限;epoll 通過(guò)調(diào)用文件描述符的回調(diào)函數(shù),使得單個(gè)進(jìn)程能夠監(jiān)控大量的事件
  • select 與 poll 返回的是整個(gè)數(shù)組的文件描述符,應(yīng)用程序需要遍歷整個(gè)數(shù)組才知道誰(shuí)觸發(fā)了事件;epoll 只返回觸發(fā)了事件的文件描述符

4. Epoll 的 LT 模式與 ET 模式的區(qū)別

  • LT 模式:高速工作模式,只支持no_block(非阻塞模式)。在此模式下,當(dāng)描述符從未就緒變?yōu)榫途w時(shí),內(nèi)核通過(guò)epoll告知。然后它會(huì)假設(shè)用戶(hù)知道文件描述符已經(jīng)就緒,并且不會(huì)再為那個(gè)文件描述符發(fā)送更多的就緒通知,直到某些操作導(dǎo)致那個(gè)文件描述符不再為就緒狀態(tài)了。(觸發(fā)模式只在數(shù)據(jù)就緒時(shí)通知一次,若數(shù)據(jù)沒(méi)有讀完,下一次不會(huì)通知,直到有新的就緒數(shù)據(jù))
  • ET 模式:缺省工作方式,支持blocksocket和no_blocksocket。在LT模式下內(nèi)核會(huì)告知一個(gè)文件描述符是否就緒了,然后可以對(duì)這個(gè)就緒的fd進(jìn)行IO操作。如果不作任何操作,內(nèi)核還是會(huì)繼續(xù)通知!若數(shù)據(jù)沒(méi)有讀完,內(nèi)核也會(huì)繼續(xù)通知,直至設(shè)備數(shù)據(jù)為空為止

5. Epoll 的紅黑樹(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容