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