日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

epoll哪些触发模式_5.epoll的水平触发和边缘触发

發布時間:2023/12/9 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 epoll哪些触发模式_5.epoll的水平触发和边缘触发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇是多路復用的第五篇,主要來講解epoll的水平觸發和邊緣觸發是怎么回事。

一、概念介紹

EPOLL事件有兩種模型,水平出發和邊緣觸發,如下所示:

1. Level Triggered (LT) 水平觸發

1. socket接收緩沖區不為空 有數據可讀 讀事件一直觸發2. socket發送緩沖區不滿 可以繼續寫入數據 寫事件一直觸發備注:符合思維習慣,epoll_wait返回的事件就是socket的狀態

例子介紹:

1.?accept一個連接,添加到epoll中監聽EPOLLIN事件2.?當EPOLLIN事件到達時,read?fd中的數據并處理3.?當需要寫出數據時,把數據write到fd中;如果數據較大,無法一次性寫出,那么在epoll中監聽EPOLLOUT事件4.?當EPOLLOUT事件到達時,繼續把數據write到fd中;如果數據寫出完畢,那么在epoll中關閉EPOLLOUT事件

2. Edge Triggered (ET) 邊沿觸發

1. socket的接收緩沖區狀態變化時觸發讀事件,即空的接收緩沖區剛接收到數據時觸發讀事件2. socket的發送緩沖區狀態變化時觸發寫事件,即滿的緩沖區剛空出空間時觸發讀事件備注:僅在狀態變化時觸發事件

例子介紹:

1.?accept一個一個連接,添加到epoll中監聽EPOLLIN|EPOLLOUT事件2.?當EPOLLIN事件到達時,read?fd中的數據并處理,read需要一直讀,直到返回EAGAIN為止3.?當需要寫出數據時,把數據write到fd中,直到數據全部寫完,或者write返回EAGAIN4.?當EPOLLOUT事件到達時,繼續把數據write到fd中,直到數據全部寫完,或者write返回EAGAIN

3.LT和ET兩者比較:

1. 從ET的處理過程中可以看到,ET的要求是需要一直讀寫,直到返回EAGAIN,否則就會遺漏事件。ET的編程可以做到更加簡潔,某些場景下更加高效,但另一方面容易遺漏事件,容易產生bug。2. LT的處理過程中,直到返回EAGAIN不是硬性要求,但通常的處理過程都會讀寫直到返回EAGAIN,但LT比ET多了一個開關EPOLLOUT事件的步驟。LT的編程與poll/select接近,符合一直以來的習慣,不易出錯。

二?、內核調度實現方式

  • 在epoll_wait的時候,阻塞等待事件發生, 事件發生時通過回調掛到ready list鏈表中

  • epoll_wait返回, 處理ready list, 返回事件給調用者

  • 此時ET模式已經將事件從ready list中刪除,LT模式中還存在

  • 此時假設應用程序處理完了事件, 再次epoll_wait. ?ET模式繼續阻塞

  • LT模式由于ready list中依然存在事件則不會阻塞, 對這些socket調用poll方法獲取最新的事件信息,如果確認沒事件了才會刪除。

三、?水平觸發和邊緣觸發的常見問題

1. 水平觸發的問題:不必要的喚醒

  • 內核:收到一個新建連接的請求

  • 內核:由于 “驚群效應” ,喚醒兩個正在 epoll_wait() 的線程 A 和線程 B

  • 線程A:epoll_wait() 返回

  • 線程B:epoll_wait() 返回

  • 線程A:執行 accept() 并且成功

  • 線程B:執行 accept() 失敗,accept() 返回 EAGAIN

  • 2. 邊緣觸發的問題:不必要的喚醒以及饑餓

    1)不必要的喚醒:

    1.內核:收到第一個連接請求。線程 A 和 線程 B 兩個線程都在 epoll_wait() 上等待。由于采用邊緣觸發模式,所以只有一個線程會收到通知。這里假定線程 A 收到通知2.線程A:epoll_wait() 返回3.線程A:調用 accpet() 并且成功4.內核:此時 accept queue 為空,所以將邊緣觸發的 socket 的狀態從可讀置成不可讀5.內核:收到第二個建連請求6.內核:此時,由于線程 A 還在執行 accept() 處理,只剩下線程 B 在等待 epoll_wait(),于是喚醒線程 B。7.線程A:繼續執行 accept() 直到返回 EAGAIN8.線程B:執行 accept(),并返回 EAGAIN,此時線程 B 可能有點困惑(“明明通知我有事件,結果卻返回 EAGAIN”)9.線程A:再次執行 accept(),這次終于返回 EAGAIN

    2)饑餓:

    1.內核:接收到兩個建連請求。線程 A 和 線程 B 兩個線程都在等在 epoll_wait()。由于采用邊緣觸發模式,只有一個線程會被喚醒,我們這里假定線程 A 先被喚醒2.線程A:epoll_wait() 返回3.線程A:調用 accpet() 并且成功4.內核:收到第三個建連請求。由于線程?A?還沒有處理完(沒有返回?EAGAIN),當前?socket?還處于可讀的狀態,由于是邊緣觸發模式,所有不會產生新的事件5.線程A:繼續執行 accept() 希望返回 EAGAIN 再進入 epoll_wait() 等待,然而它又 accept() 成功并處理了一個新連接6.內核:又收到了第四個建連請求7.線程A:又繼續執行 accept(),結果又返回成功

    參考文檔:

    https://blog.csdn.net/dongfuye/article/details/50880251

    https://www.zhihu.com/question/20502870

    https://blog.lucode.net/linux/epoll-tutorial.html

    https://plantegg.github.io/2019/12/09/epoll%E7%9A%84LT%E5%92%8CET/

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的epoll哪些触发模式_5.epoll的水平触发和边缘触发的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。