0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

epoll的觸發(fā)模式介紹

科技綠洲 ? 來源:Linux開發(fā)架構(gòu)之路 ? 作者:Linux開發(fā)架構(gòu)之路 ? 2023-11-10 14:54 ? 次閱讀

前言

epoll的觸發(fā)模式是個引發(fā)討論非常多的話題網(wǎng)絡(luò)上這方面總結(jié)的文章也很多,首先從名字上就不是很統(tǒng)一,LT模式常被稱為水平觸發(fā)、電平觸發(fā)、條件觸發(fā),而ET模式常被稱為邊緣觸發(fā)、邊沿觸發(fā)等,這些都是從英文翻譯過來的,只不過翻譯的時候有些差異,LT全稱 level-triggered,ET全稱 edge-triggered。

雖然這個知識點(diǎn)熱度很高,但很多人對于它的理解總是差那么一點(diǎn),特別是在面試的時候,很多面試者總是處于一種回憶和背誦的狀態(tài),其實(shí)這兩種模式真的不需要去死記硬背,下面說說我個人對這兩種模式的理解和記憶方法。

名稱的記憶

每次提到ET(邊沿觸發(fā))首先映入我腦海的是大學(xué)里《數(shù)字邏輯電路》這門課程,里面會提到低電平、高電平,當(dāng)電平從低到高時會有一個上升沿,而電平從高到低時會有一個下降沿,這個“沿”就是邊沿觸發(fā)時提到的“邊沿”,跟馬路邊的馬路牙子是同一種概念,也就是指狀態(tài)變化的時候。提起上升沿和下降沿我還是印象很深的,當(dāng)時我可是占用了好幾節(jié)課的時間用Verilog語言寫了一個顯示“HELLO WORLD”的仿真波形,依靠的就是電平變化中的“沿”。

狀態(tài)變化

LT模式和ET模式可以類比電平變化來學(xué)習(xí),但是在實(shí)際應(yīng)用中概念卻不是完全一樣的,在epoll的應(yīng)用中涉及到關(guān)于IO的讀寫,而讀寫的狀態(tài)變化有哪些呢?可讀、不可讀、可寫、不可寫,其實(shí)就是這四種狀態(tài)而已,以socket為例。

可讀:socket上有數(shù)據(jù)

不可讀:socket上沒有數(shù)據(jù)了

可寫:socket上有空間可寫

不可寫:socket上無空間可寫

對于水平觸發(fā)模式,一個事件只要有,就會一直觸發(fā)。
對于邊緣觸發(fā)模式,只有一個事件從無到有才會觸發(fā)。

LT模式

對于讀事件 EPOLLIN,只要socket上有未讀完的數(shù)據(jù),EPOLLIN 就會一直觸發(fā);對于寫事件 EPOLLOUT,只要socket可寫(一說指的是 TCP 窗口一直不飽和,我覺得是TCP緩沖區(qū)未滿時,這一點(diǎn)還需驗(yàn)證),EPOLLOUT 就會一直觸發(fā)。

在這種模式下,大家會認(rèn)為讀數(shù)據(jù)會簡單一些,因?yàn)榧词箶?shù)據(jù)沒有讀完,那么下次調(diào)用epoll_wait()時,它還會通知你在上沒讀完的文件描述符上繼續(xù)讀,也就是人們常說的這種模式不用擔(dān)心會丟失數(shù)據(jù)。

而寫數(shù)據(jù)時,因?yàn)槭褂?LT 模式會一直觸發(fā) EPOLLOUT 事件,那么如果代碼實(shí)現(xiàn)依賴于可寫事件觸發(fā)去發(fā)送數(shù)據(jù),一定要在數(shù)據(jù)發(fā)送完之后移除檢測可寫事件,避免沒有數(shù)據(jù)發(fā)送時無意義的觸發(fā)。

ET模式

對于讀事件 EPOLLIN,只有socket上的數(shù)據(jù)從無到有,EPOLLIN 才會觸發(fā);對于寫事件 EPOLLOUT,只有在socket寫緩沖區(qū)從不可寫變?yōu)榭蓪懀?code>EPOLLOUT 才會觸發(fā)(剛剛添加事件完成調(diào)用epoll_wait時或者緩沖區(qū)從滿到不滿)

這種模式聽起來清爽了很多,只有狀態(tài)變化時才會通知,通知的次數(shù)少了自然也會引發(fā)一些問題,比如觸發(fā)讀事件后必須把數(shù)據(jù)收取干凈,因?yàn)槟悴灰欢ㄓ邢乱淮螜C(jī)會再收取數(shù)據(jù)了,即使不采用一次讀取干凈的方式,也要把這個激活狀態(tài)記下來,后續(xù)接著處理,否則如果數(shù)據(jù)殘留到下一次消息來到時就會造成延遲現(xiàn)象。

這種模式下寫事件觸發(fā)后,后續(xù)就不會再觸發(fā)了,如果還需要下一次的寫事件觸發(fā)來驅(qū)動發(fā)送數(shù)據(jù),就需要再次注冊一次檢測可寫事件。

數(shù)據(jù)的讀取和發(fā)送

關(guān)于數(shù)據(jù)的讀比較好理解,無論是LT模式還是ET模式,監(jiān)聽到讀事件從socket開始讀數(shù)據(jù)就好了,只不過讀的邏輯有些差異,LT模式下,讀事件觸發(fā)后,可以按需收取想要的字節(jié)數(shù),不用把本次接收到的數(shù)據(jù)收取干凈,ET模式下,讀事件觸發(fā)后通常需要數(shù)據(jù)一次性收取干凈。

而數(shù)據(jù)的寫不太容易理解,因?yàn)閿?shù)據(jù)的讀是對端發(fā)來數(shù)據(jù)導(dǎo)致的,而數(shù)據(jù)的寫其實(shí)是自己的邏輯層觸發(fā)的,所以在通過網(wǎng)絡(luò)發(fā)數(shù)據(jù)時通常都不會去注冊監(jiān)可寫事件,一般都是調(diào)用 send 或者 write 函數(shù)直接發(fā)送,如果發(fā)送過程中, 函數(shù)返回 -1,并且錯誤碼是 EWOULDBLOCK 表明發(fā)送失敗,此時才會注冊監(jiān)聽可寫事件,并將剩余的服務(wù)存入自定義的發(fā)送緩沖區(qū)中,等可寫事件觸發(fā)后再接著將發(fā)送緩沖區(qū)中剩余的數(shù)據(jù)發(fā)送出去。

代碼實(shí)踐

基礎(chǔ)代碼

以下為一個epoll觸發(fā)模式測試的基礎(chǔ)代碼,也不算太長,直接拿來就可以測試:

#include < sys/socket.h > //for socket
#include < arpa/inet.h >  //for htonl htons
#include < sys/epoll.h >  //for epoll_ctl
#include < unistd.h >     //for close
#include < fcntl.h >      //for fcntl
#include < errno.h >      //for errno
#include < iostream >     //for cout

class fd_object
{
public:
    fd_object(int fd) { listen_fd = fd; }
    ~fd_object() { close(listen_fd); }
private:
    int listen_fd;
};

/*
./epoll for lt mode
and
./epoll 1 for et mode
*/
int main(int argc, char* argv[])
{
    //create a socket fd
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1)
    {
        std::cout < < "create listen socket fd error." < < std::endl;
        return -1;
    }
    fd_object obj(listen_fd);

    //set socket to non-block
    int socket_flag = fcntl(listen_fd, F_GETFL, 0);
    socket_flag |= O_NONBLOCK;
    if (fcntl(listen_fd, F_SETFL, socket_flag) == -1)
    {
        std::cout < < "set listen fd to nonblock error." < < std::endl;
        return -1;
    }

    //init server bind info
    int port = 51741;
    struct sockaddr_in bind_addr;
    bind_addr.sin_family = AF_INET;
    bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    bind_addr.sin_port = htons(port);
    if (bind(listen_fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) == -1)
    {
        std::cout < < "bind listen socket fd error." < < std::endl;
        return -1;
    }

    //start listen
    if (listen(listen_fd, SOMAXCONN) == -1)
    {
        std::cout < < "listen error." < < std::endl;
        return -1;
    }
    else
        std::cout < < "start server at port [" < < port < < "] with [" < < (argc <= 1 ? "LT" : "ET") < < "] mode." < < std::endl;

    //create a epoll fd
    int epoll_fd = epoll_create(88);
    if (epoll_fd == -1)
    {
        std::cout < < "create a epoll fd error." < < std::endl;
        return -1;
    }

    epoll_event listen_fd_event;
    listen_fd_event.data.fd = listen_fd;
    listen_fd_event.events = EPOLLIN;
    if (argc > 1) listen_fd_event.events |= EPOLLET;

    //add epoll event for listen fd
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &listen_fd_event) == -1)
    {
        std::cout < < "epoll ctl error." < < std::endl;
        return -1;
    }

    while (true)
    {
        epoll_event epoll_events[1024];
        int n = epoll_wait(epoll_fd, epoll_events, 1024, 1000);

        if (n < 0)
            break;
        else if (n == 0) //timeout
            continue;

        for (int i = 0; i < n; ++i)
        {
            if (epoll_events[i].events & EPOLLIN)//trigger read event
            {
                if (epoll_events[i].data.fd == listen_fd)
                {
                    //accept a new connection
                    struct sockaddr_in client_addr;
                    socklen_t client_addr_len = sizeof(client_addr);
                    int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
                    if (client_fd == -1)
                        continue;

                    socket_flag = fcntl(client_fd, F_GETFL, 0);
                    socket_flag |= O_NONBLOCK;
                    if (fcntl(client_fd, F_SETFL, socket_flag) == -1)
                    {
                        close(client_fd);
                        std::cout < < "set client fd to non-block error." < < std::endl;
                        continue;
                    }

                    epoll_event client_fd_event;
                    client_fd_event.data.fd = client_fd;
                    client_fd_event.events = EPOLLIN | EPOLLOUT;
                    if (argc > 1) client_fd_event.events |= EPOLLET;

                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_fd_event) == -1)
                    {
                        std::cout < < "add client fd to epoll fd error." < < std::endl;
                        close(client_fd);
                        continue;
                    }

                    std::cout < < "accept a new client fd [" < < client_fd < < "]." < < std::endl;
                }
                else
                {
                    std::cout < < "EPOLLIN event triggered for client fd [" < < epoll_events[i].data.fd < < "]." < < std::endl;

                    char recvbuf[1024] = { 0 };
                    int m = recv(epoll_events[i].data.fd, recvbuf, 1, 0); // only read 1 bytes when read event triggered

                    if (m == 0 || (m < 0 && errno != EWOULDBLOCK && errno != EINTR))
                    {
                        if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1)
                            std::cout < < "the client fd [" < < epoll_events[i].data.fd < < "] disconnected." < <  std::endl;
                        close(epoll_events[i].data.fd);
                    }

                    std::cout < < "recv data from client fd [" < < epoll_events[i].data.fd < < "] and data is [" < < recvbuf < < "]." < < std::endl;
                }
            }
            else if (epoll_events[i].events & EPOLLOUT)
            {
                if (epoll_events[i].data.fd == listen_fd) //trigger write event
                    continue;

                std::cout < < "EPOLLOUT event triggered for client fd [" < < epoll_events[i].data.fd < < "]." < < std::endl;
            }
        }
    }

    return 0;
}

簡單說下這段代碼的測試方法,可以使用 g++ testepoll.cpp -o epoll 進(jìn)行編譯,編譯后通過 ./epoll 運(yùn)行為LT模式,通過 ./epoll et模式運(yùn)行為ET模式,我們用編譯好的epoll程序作為服務(wù)器,使用nc命令來模擬一個客戶端。

測試分類

1.編譯后直接./epoll,然后在另一個命令行窗口用 nc -v 127.0.0.1 51741 命令模擬一次連接,此時 ./epoll 會產(chǎn)生大量的 EPOLLOUT event triggered for client fd ...,那是因?yàn)樵贚T模式下,EPOLLOUT會被一直觸發(fā)。

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll
start server at port [51741] with [LT] mode.
accept a new client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLOUT event triggered for client fd [5].
...

2.注釋包含 EPOLLOUT event triggered for client fd 輸出內(nèi)容的第152行代碼,編譯后 ./epoll運(yùn)行,然后在另一個命令行窗口用 nc -v 127.0.0.1 51741 模擬一次連接后,輸入abcd回車,可以看到服務(wù)器./epoll輸出內(nèi)容,EPOLLIN被觸發(fā)多次,每次讀取一個字節(jié)。

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll
start server at port [51741] with [LT] mode.
accept a new client fd [5].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [a].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [b].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [c].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [d].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].

3.還原剛才注釋的那行代碼,編譯后執(zhí)行 ./epoll et 啟動服務(wù)器,然后在另一個命令行窗口用 nc -v 127.0.0.1 51741 模擬一次連接后,然后在另一個命令行窗口用 nc -v 127.0.0.1 51741 模擬一次連接,服務(wù)器窗口顯示觸發(fā)了EPOLLOUT事件

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll et
start server at port [51741] with [ET] mode.
accept a new client fd [5].
EPOLLOUT event triggered for client fd [5].

在此基礎(chǔ)上,從剛剛運(yùn)行nc命令的窗口中輸入回車、輸入回車、輸出回車,那么epoll服務(wù)器窗口看到的是觸發(fā)了三次EPOLLIN事件,每次收到一個回車:

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll et
start server at port [51741] with [ET] mode.
accept a new client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].

但是如果在nc模擬的客戶端里輸出abcd回車,那么在epoll服務(wù)器窗口觸發(fā)一次EPOLLIN事件接收到一個a之后便再也不會觸發(fā)EPOLLIN了,即使你在nc客戶端在此輸入也沒有用,那是因?yàn)樵诮邮艿木彌_區(qū)中一直還有數(shù)據(jù),新數(shù)據(jù)來時沒有出現(xiàn)緩沖區(qū)從空到有數(shù)據(jù)的情況,所以在ET模式下也注意這種情況。

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll et
start server at port [51741] with [ET] mode.
accept a new client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [a].

怎么解決ET觸發(fā)了一次就不再觸發(fā)了

改代碼唄,ET模式在連接后觸發(fā)一次EPOLLOUT,接收到數(shù)據(jù)時觸發(fā)一次EPOLLIN,如果數(shù)據(jù)沒收完,以后這兩個事件就再也不會被觸發(fā)了,要想改變這種情況可以再次注冊一下這兩個事件,時機(jī)可以選擇接收到數(shù)據(jù)的時候,所以可以修改這部分代碼:

else
{
    std::cout < < "EPOLLIN event triggered for client fd [" < < epoll_events[i].data.fd < < "]." < < std::endl;

    char recvbuf[1024] = { 0 };
    int m = recv(epoll_events[i].data.fd, recvbuf, 1, 0); // only read 1 bytes when read event triggered

    if (m == 0 || (m < 0 && errno != EWOULDBLOCK && errno != EINTR))
    {
        if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1)
            std::cout < < "the client fd [" < < epoll_events[i].data.fd < < "] disconnected." < <  std::endl;
        close(epoll_events[i].data.fd);
    }

    std::cout < < "recv data from client fd [" < < epoll_events[i].data.fd < < "] and data is [" < < recvbuf < < "]." < < std::endl;
}

添加再次注冊的邏輯:

else
{
    std::cout < < "EPOLLIN event triggered for client fd [" < < epoll_events[i].data.fd < < "]." < < std::endl;

    char recvbuf[1024] = { 0 };
    int m = recv(epoll_events[i].data.fd, recvbuf, 1, 0); // only read 1 bytes when read event triggered

    if (m == 0 || (m < 0 && errno != EWOULDBLOCK && errno != EINTR))
    {
        if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1)
            std::cout < < "the client fd [" < < epoll_events[i].data.fd < < "] disconnected." < <  std::endl;
        close(epoll_events[i].data.fd);
    }

    epoll_event client_fd_event;
    client_fd_event.data.fd = epoll_events[i].data.fd;
    client_fd_event.events = EPOLLIN | EPOLLOUT;
    if (argc > 1) client_fd_event.events |= EPOLLET;

    epoll_ctl(epoll_fd, EPOLL_CTL_MOD, epoll_events[i].data.fd, &client_fd_event);

    std::cout < < "recv data from client fd [" < < epoll_events[i].data.fd < < "] and data is [" < < recvbuf < < "]." < < std::endl;
}

這次以./epoll et方式啟動服務(wù)器,使用nc -v 127.0.0.1 51741模擬客戶端,輸入abc回車發(fā)現(xiàn),epoll服務(wù)器輸出顯示觸發(fā)的事件變了:

albert@home-pc:/mnt/d/data/cpp/testepoll$ ./epoll et
start server at port [51741] with [ET] mode.
accept a new client fd [5].
EPOLLOUT event triggered for client fd [5].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [a].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [b].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [c].
EPOLLIN event triggered for client fd [5].
recv data from client fd [5] and data is [
].
EPOLLOUT event triggered for client fd [5].

總結(jié)

  • LT模式會一直觸發(fā)EPOLLOUT,當(dāng)緩沖區(qū)有數(shù)據(jù)時會一直觸發(fā)EPOLLIN
  • ET模式會在連接建立后觸發(fā)一次EPOLLOUT,當(dāng)收到數(shù)據(jù)時會觸發(fā)一次EPOLLIN
  • LT模式觸發(fā)EPOLLIN時可以按需讀取數(shù)據(jù),殘留了數(shù)據(jù)還會再次通知讀取
  • ET模式觸發(fā)EPOLLIN時必須把數(shù)據(jù)讀取完,否則即使來了新的數(shù)據(jù)也不會再次通知了
  • LT模式的EPOLLOUT會一直觸發(fā),所以發(fā)送完數(shù)據(jù)記得刪除,否則會產(chǎn)生大量不必要的通知
  • ET模式的EPOLLOUT事件若數(shù)據(jù)未發(fā)送完需再次注冊,否則不會再有發(fā)送的機(jī)會
  • 通常發(fā)送網(wǎng)絡(luò)數(shù)據(jù)時不會依賴EPOLLOUT事件,只有在緩沖區(qū)滿發(fā)送失敗時會注冊這個事件,期待被通知后再次發(fā)送
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 邏輯電路
    +關(guān)注

    關(guān)注

    13

    文章

    492

    瀏覽量

    42535
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6808

    瀏覽量

    88743
  • 電平
    +關(guān)注

    關(guān)注

    5

    文章

    357

    瀏覽量

    39812
  • epoll
    +關(guān)注

    關(guān)注

    0

    文章

    28

    瀏覽量

    2941
收藏 人收藏

    評論

    相關(guān)推薦

    示波器的觸發(fā)模式與使用方法

    示波器的“觸發(fā)”就是使得示波器的掃描與被觀測信號同步,從而顯示穩(wěn)定的波形。為滿足不同的觀測需要,需要不同的“觸發(fā)模式”。示波器的基本觸發(fā)模式
    發(fā)表于 08-25 15:10 ?1.2w次閱讀

    epoll的使用

    以下內(nèi)容是參考華清遠(yuǎn)見《linux/unix系統(tǒng)編程手冊》對epoll的一個個人總結(jié),是我在華清遠(yuǎn)見比較全面的總結(jié)。一、epoll的優(yōu)點(diǎn)同I/O多路復(fù)用和信號驅(qū)動I/O一樣,linux的epoll
    發(fā)表于 05-11 13:22

    我讀過的最好的epoll講解

    多個流了,但這樣的做法顯然不好,因?yàn)槿绻械牧鞫紱]有數(shù)據(jù),那么只會白白浪費(fèi)CPU。這里要補(bǔ)充一點(diǎn),阻塞模式下,內(nèi)核對于I/O事件的處理是阻塞或者喚醒,而非阻塞模式下則把I/O事件交給其他對象(后文介紹
    發(fā)表于 05-12 15:30

    epoll使用方法與poll的區(qū)別

    因?yàn)?b class='flag-5'>epoll的觸發(fā)機(jī)制是在內(nèi)核中直接完成整個功能 那個事件準(zhǔn)備就緒我就直接返回這個IO事件
    發(fā)表于 07-31 10:03

    epoll_wait的事件返回的fd為錯誤是怎么回事?

    netlink 的 socket 連接 的 fd 為18,但是添加到epollepoll_wait()返回的fd 為 0為什么會出現(xiàn)這樣的現(xiàn)象?補(bǔ)充 說明:1、 epoll_wait返回
    發(fā)表于 06-12 09:03

    揭示EPOLL一些原理性的東西

    事件交給其他對象(后文介紹的select以及epoll)處理甚至直接忽略。為了避免CPU空轉(zhuǎn),可以引進(jìn)了一個代理(一開始有一位叫做select的代理,后來又有一位叫做poll的代理,不過兩者的本質(zhì)是一樣
    發(fā)表于 08-24 16:32

    重復(fù)采樣模式,單次采樣模式,自動模式觸發(fā)模式

    重復(fù)采樣模式與單次采樣模式  過去,最常見的示波器運(yùn)行模式是重復(fù)模式。這意味著一旦示波器觸發(fā)并將數(shù)據(jù)顯示給用戶,它將立即開始搜索下一個
    發(fā)表于 10-10 15:46 ?1241次閱讀

    示波器觸發(fā)電路的體系結(jié)構(gòu)和高級觸發(fā)功能的介紹

    在使用示波器時,必須了解需要使用哪種觸發(fā)來捕獲特定事件。本文將首先探討示波器觸發(fā)電路的典型體系結(jié)構(gòu),然后介紹基本觸發(fā)模式,最后討論現(xiàn)有的一些
    的頭像 發(fā)表于 07-18 08:02 ?5343次閱讀
    示波器<b class='flag-5'>觸發(fā)</b>電路的體系結(jié)構(gòu)和高級<b class='flag-5'>觸發(fā)</b>功能的<b class='flag-5'>介紹</b>

    poll&&epollepoll實(shí)現(xiàn)

    poll&&epollepoll實(shí)現(xiàn)
    發(fā)表于 05-14 14:34 ?2766次閱讀
    poll&&<b class='flag-5'>epoll</b>之<b class='flag-5'>epoll</b>實(shí)現(xiàn)

    一文詳解epoll的實(shí)現(xiàn)原理

    本文以四個方面介紹epoll的實(shí)現(xiàn)原理,1.epoll的數(shù)據(jù)結(jié)構(gòu);2.協(xié)議棧如何與epoll通信;3.epoll線程安全如何加鎖;4.ET與
    的頭像 發(fā)表于 08-01 13:28 ?3986次閱讀

    epoll來實(shí)現(xiàn)多路復(fù)用

    本人用epoll來實(shí)現(xiàn)多路復(fù)用,epoll觸發(fā)模式有兩種: ET(邊緣模式) LT(水平模式
    的頭像 發(fā)表于 11-09 10:15 ?467次閱讀
    用<b class='flag-5'>epoll</b>來實(shí)現(xiàn)多路復(fù)用

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

    今兒我們就從源碼入手,來幫助大家簡單理解一下 epoll 的實(shí)現(xiàn)原理,并在后邊分析一下,大家都說 epoll 性能好,那到底是好在哪里。 epoll 簡介 1、epoll 的簡單使用
    的頭像 發(fā)表于 11-09 11:14 ?497次閱讀
    <b class='flag-5'>epoll</b> 的實(shí)現(xiàn)原理

    epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

    一、epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu) 在開始研究源代碼之前,我們先看一下 epoll 中使用的數(shù)據(jù)結(jié)構(gòu),分別是 eventpoll、epitem 和 eppoll_entry。 1、eventpoll 我們
    的頭像 發(fā)表于 11-10 10:20 ?749次閱讀
    <b class='flag-5'>epoll</b>的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

    epoll的LT模式總結(jié)

    epoll觸發(fā)模式是個引發(fā)討論非常多的話題,網(wǎng)絡(luò)上這方面總結(jié)的文章也很多,首先從名字上就不是很統(tǒng)一,LT模式常被稱為水平觸發(fā)、電平
    的頭像 發(fā)表于 11-10 15:35 ?453次閱讀

    epoll源碼分析

    Linux內(nèi)核提供了3個關(guān)鍵函數(shù)供用戶來操作epoll,分別是: epoll_create(), 創(chuàng)建eventpoll對象 epoll_ctl(), 操作eventpoll對象
    的頭像 發(fā)表于 11-13 11:49 ?961次閱讀
    <b class='flag-5'>epoll</b>源碼分析