receive(), fget(), read()等函式都是阻塞讀。
對於運用層:
將所有等待的輸入事件都進行監控,只要其中乙個就緒,就往下走,乙個都沒有就緒就一直等(也可設定超時),
此時監控池只知道「反正至少有乙個就緒了,具體是誰並不知道」。
往下走時用if分支對所有的監控物件(輸入事件)進行輪詢,看究竟是哪乙個就緒。
對於核心層(驅動):
光運用層使用select()、poll()、epoll()而底層沒有與之相配合的阻塞機制那是不奏效的,所以驅動必須要有相對應的函式配合。
對於驅動而言:既然我是被監控的物件,那我沒資料可讀(或者沒空間可寫)時得上報,有資料可讀(或者有空間可寫)時也得通知
一下運用層,不然poll()、epoll()怎麼知道我就緒了。
驅動層中這個機制是操作方法集中的乙個函式介面的實現(與open同級),這個過程中用到的最重要的函式就是poll_wait().
通知運用層的方式是return mask,這個mask會攜帶是否就緒的資訊。
select() ,poll() , epoll(),
只告訴應用層:「反正是有人產生了事件了,可以來處理了,
但具體是誰產生了什麼事我根本不知道,你再去乙個個問吧」
/*
* 功能:
* 輸入引數:__nfds: 最大檔案描述符加1
* fd_set * __readfds: 讀集
* fd_set * __writefds: 寫集
* fd_set * __exceptfds: 異常集
* struct timeval *__timeout: 超時時間(0表示永不超時,即阻塞)
*/int
select (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout);
/*
* 功能: 將檔案描述符加到監控池
*/fd_set(int fd, fdset *set)
/*
* 功能: 清空監控池
*/fd_zero(fdset *set)
/*
* 功能: 將某個檔案描述符從監控池中刪除
*/fd_clr(int fd, fdset *set)
/*
* 功能: 檢查監控池中某個檔案描述符是否有事件就緒
*/fd_isset(int fd, fdset *set)
只告訴應用層:「反正是有人產生了事件了,可以來處理了,
我可以告訴你是寫事件還是讀事件,但具體是誰產生了,你再去乙個個問吧」。
它用陣列管理物件,避免了select要與fd_set等函式配合的繁瑣步驟,
並且相比select至少可以從renents中知道是寫還是讀,
加入監控池之前也可以選擇events是監控寫還是監控讀。
/*
* 其中乙個形參的型別說明
*/struct pollfd
/*
* 功能: 監控池
* 輸入引數:struct pollfd *fds:監控結構的首位址
* nfds_t nfds: 陣列長度
* int timeout: 超時時間(0表示永不超時,即阻塞)
*/int poll(struct pollfd *fds, nfds_t nfds, int timeout);
時間效率高,但空間效率低。
他不僅知道有事件產生,還把產生的是誰,是什麼事件放在renvents中供使用者查詢。
告訴應用層說:「有人產生事件了,
我已經將產生這個事件的人和產生的什麼事件放到revents中了,
人髒俱獲,請君檢視」
typedef
union epoll_data epoll_data_t;
struct epoll_event ;
/*
* 功能:建立乙個監控池
* 輸入引數: size:監控池大小,最多監控幾項
* 返回值:epoll的控制代碼(相當於檔案描述符)
*/int epoll_create(int
size);
/*
* 功能:對epoll的屬性進行設定
* 輸入引數:int epfd: epoll的控制代碼
* int op: 命令選項,epoll_ctl_add增,epoll_ctl_del刪,epoll_ctl_mod切換為輸入/輸出
* int fd: 要監控的使用者檔案描述符
* struct epoll_event *event: 使用者要監控的事件是輸入還是輸出
*/int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
/*
* 功能:監控,等待事件發生,
* 輸入引數:epfd: epoll控制代碼
* maxevents: 最大描述符夾1
* timeout: 超時時間(0永不超時)
* 輸出引數:struct epoll revents:反饋回來的事件,就緒的是輸入/還是輸出
io多路復用例項分析.doc
我寫的乙個基於epoll多路復用的socket伺服器端,支援乙太網卡各項引數的查詢與修改
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const
char __user *, size_t, loff_t *);
unsigned
int (*poll) (struct file *, struct poll_table_struct *); //io多路復用的函式介面
long (*unlocked_ioctl) (struct file *, unsigned
int, unsigned
long);
...
/*
* 功能:向poll_table中註冊等待佇列
* 輸入引數:filp: 上層傳進來的檔案控制代碼
* queue:等待佇列
* wait: 監控列表
* 返回值:none
見另一篇部落格,將poll操作方法及等待佇列的:
等待佇列
更詳細的解釋見部落格:
I O多路復用
一 五種i o模型 1 阻塞i o模型 最流行的i o模型是阻塞i o模型,預設情形下,所有套介面都是阻塞的。我們以資料報套介面為例來講解此模型 我們使用udp而不是tcp作為例子的原因在於就udp而言,資料準備好讀取的概念比較簡單 要麼整個資料報已經收到,要麼還沒有。然而對於tcp來說,諸如套介面...
i o多路復用
最常見的i o多路復用就是 select poll epoll了,下面說說他們的一些特點和區別吧。select 可讀 可寫 異常三種檔案描述符集的申明和初始化。fd set readfds,writefds,exceptionfds fd zero readfds fd zero writefds ...
I O多路復用
我們都知道unix like 世界裡,一切皆檔案,而檔案是什麼呢?檔案就是一串二進位製流而已,不管socket,還是fifo 管道 終端,對我們來說,一切都是檔案,一切都是流。在資訊 交換的過程中,我們都是對這些流進行資料的收發操作,簡稱為i o操作 input and output 往流中讀出資料...