Linux :IO多路复用模型
轉(zhuǎn)載:http://blog.csdn.net/mr253727942/article/details/50827127
一、IO多路復(fù)用定義
IO多路復(fù)用允許應(yīng)用在多個文件描述符上阻塞,并在某一個可以讀寫時通知, 一般遵循下面的設(shè)計原則:、
Linux下提供了三種IO多路復(fù)用方案,select、poll和epoll。
二、select IO 多路復(fù)用
看一下select 函數(shù)的定義:
int select (int n,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);FD_CLR(int fd, fd_set *set);FD_ISSET(int fd, fd_set *set);FD_SET(int fd, fd_set *set);FD_ZERO(fd_set *set);上面的定義中可以看到select主要檢測三類文件描述符,分別等待不同的事件。
-
readfds
確認(rèn)是否有可讀數(shù)據(jù) -
writefds
確認(rèn)是否有可寫數(shù)據(jù) -
exceptefds
確認(rèn)是否有異常發(fā)生或者出現(xiàn)帶外數(shù)據(jù)。
第一個參數(shù)n,等于所有集合中文件描述符的最大值加一。select()的調(diào)用者需要找到最大的文件描述符值加一作為第一個參數(shù)。
成功返回時,返回哪一個文件描述符,就說明該文件描述符準(zhǔn)備好無阻塞IO。對于timeout,select操作可以設(shè)置一個超時時間,超時后即使沒有文件描述符IO就緒也會返回。
select的缺點:
1.每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài)?
2。同時需要遍歷所有fd?
3。支持的文件描述符默認(rèn)只有1024
三、poll IO 多路復(fù)用
poll()系統(tǒng)調(diào)用也是一個IO多路復(fù)用解決方案,解決了 一些select的不足,下面給出poll的定義:
#include <sys/poll.h> int poll (struct pollfd *fds, unsigned int nfds, int timeout);與上面的select()使用三個文件描述符集合不同,poll()使用了一個簡單的nfds個pollfd結(jié)構(gòu)體構(gòu)成的數(shù)組,fds指向該數(shù)組,結(jié)構(gòu)體定義如下:
#include <sys/poll.h> struct pollfd {int fd; /* file descriptor */short events; /* requested events to watch */short revents; /* returned events witnessed */ };每個pollfd指定了唯一一個文件描述符,每個結(jié)構(gòu)體中的events字段是要堅實的文件描述符事件的一組位掩碼。revents字段是發(fā)生在該文件描述符上的事件的位掩碼,內(nèi)核在返回時設(shè)置這個字段,所有events字段請求的時間都可能在revents字段中返回。下面是合法的事件:
POLLIN 沒有數(shù)據(jù)可讀 POLLRDNORM 有正常數(shù)據(jù)可讀。 POLLRDBAND 有優(yōu)先數(shù)據(jù)可讀。 POLLPRI 有高優(yōu)先級數(shù)據(jù)可讀。 POLLOUT 寫操作不會阻塞。 POLLWRNORM 寫正常數(shù)據(jù)不會阻塞。 POLLBAND 寫優(yōu)先數(shù)據(jù)不會阻塞。 POLLMSG 有一個sigpoll消息可用。除此之外還可能返回幾個異常信息:
POLLER 文件描述符有錯誤。 POLLHUP 文件描述符上有掛起事件。 POLLNVAL 給出的文件描述符非法。監(jiān)視一個文件描述符是否可以讀寫,可以設(shè)置events為POLLIN | POLLOUT,返回時將在revents中檢查是否有相應(yīng)標(biāo)志。如果設(shè)置了POLLIN,或者POLLOUT則代表可以操作相關(guān)事件。
timeout參數(shù)指定在任何IO就緒前需要等待時間的長度,負(fù)值表示永遠(yuǎn)等待,一個零值表示調(diào)用立即返回,列出所有為準(zhǔn)備好的IO,不等待任何時間。
四、poll()與select()的區(qū)別
poll()系統(tǒng)調(diào)用優(yōu)于select():
- poll()不需要使用者計算最大的文件描述符值加一和傳遞該參數(shù)。
- poll()在應(yīng)對較大值的文件描述符時效率更好,如果用select()監(jiān)視值為900的文件描述符–內(nèi)核需要檢查每個集合中的每個bit位,知道第九百個。
- select()的文件描述符集合是靜態(tài)大小,但是poll()可以創(chuàng)建合適大小的數(shù)組,只需要傳遞結(jié)構(gòu)體數(shù)組即可。
- select()文件描述符集合會在返回時重新創(chuàng)建,每個調(diào)用都必須要重新初始化它們。poll()系統(tǒng)調(diào)用分離了events字段和revents字段,無需改變就能重用。
- 相對于poll(),select()移植性更好
- select()提供了更好的超時方案。
五、epoll IO 多路復(fù)用
上面的兩種方式中,每次調(diào)用都需要所有被監(jiān)聽的文件描述符,內(nèi)核必須遍歷所有的文件描述符,當(dāng)文件描述符變得很大,這里的遍歷就會成為瓶頸。
epoll將監(jiān)聽注冊從實際監(jiān)聽中分離出來,完成了真正的事件等待。
1、先創(chuàng)建一個新的epoll實例:
#include <sys/epoll.h> int efpd = epoll_create (int size)size是告訴內(nèi)核大概需要監(jiān)聽的文件描述符數(shù)目。
2、控制epoll
epoll_ctl()可以向指定的epoll上下文中加入或刪除文件描述符。
#include <sys/epoll.h> int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event);頭文件
六、IO實現(xiàn)的內(nèi)核內(nèi)幕
主要涉及三個內(nèi)核子系統(tǒng):
虛擬文件系統(tǒng)
虛擬文件系統(tǒng)是linux內(nèi)核的文件操作的抽象機(jī)制,允許內(nèi)核在無需了解文件系統(tǒng)類型的情況下,使用文件系統(tǒng)函數(shù)和操作文件系統(tǒng)數(shù)據(jù)。
VFS實現(xiàn)這種抽象的方法是使用一種通用文件模型,它是所有l(wèi)inux文件系統(tǒng)的基礎(chǔ),通用文件模型提供了linux內(nèi)核文件系統(tǒng)必須遵循的框架,框架提供了了hooks支持讀寫、建立鏈接、同步等其他功能。
當(dāng)然這種方法規(guī)定了一些共性,比如必須要有inode,super block(超級塊)和目錄條目等。
頁緩存
頁緩存是一種在內(nèi)存中保存最近在磁盤文件系統(tǒng)上訪問過的數(shù)據(jù)的方式。頁緩存是內(nèi)核尋找文件系統(tǒng)數(shù)據(jù)的第一目的地。只有緩存找不到時內(nèi)核才會調(diào)用存儲子系統(tǒng)從磁盤讀數(shù)據(jù)。
linux中頁緩存大小是動態(tài)的,隨著IO操作將越來越多的數(shù)據(jù)帶入內(nèi)存,頁緩存會隨之增大,消耗更多的內(nèi)存,如果頁緩存確實消耗掉了所有空閑內(nèi)存,頁緩存會釋放最少使用頁。
頁回寫
內(nèi)核使用緩沖區(qū)來延遲寫操作,當(dāng)一個進(jìn)程發(fā)起寫請求,數(shù)據(jù)被拷貝到緩沖區(qū),這時將緩沖區(qū)標(biāo)記為“臟”數(shù)據(jù),如果對同一個數(shù)據(jù)塊有新的寫請求,緩沖區(qū)就更新為新數(shù)據(jù),把“臟”緩沖區(qū)寫入磁盤。有兩個條件會觸發(fā)這種回寫:
回寫由一些pdflush內(nèi)核線程操作,當(dāng)上述兩種情況發(fā)生,線程被喚醒開始刷新臟緩沖區(qū)。
總結(jié)
以上是生活随笔為你收集整理的Linux :IO多路复用模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 试管婴儿怎样做
- 下一篇: 宏基家用投影仪x118h使用方法