apue I/O多路轉接,select與poll

I/O多路轉接

select

傳向select的參數告訴內核:

  • 我們所關心的描述符。
  • 對於每個描述符,我們所關心的狀態(是否讀一個給定的描述符?是否寫一個給定的描述符?是否關心一個描述符的異常狀態?)。
  • 願意等待多長時間(可以永遠等待,等待一個固定量時間,或完全不等待)。

從select返回時,內核告訴我們:

  • 已經準備好的描述符的數量。
  • 對於讀、寫或異常這三個狀態中的每一個,哪些描述符已經準備好。
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
返回值:準備就緒的文件描述符數,若超時則返回0,若出錯則返回-1.

先說明最後一個參數,它指定願意等待的時間:

struct timeval {
    long tv_sec; // 秒
    long tv_usec; // 微妙
};

有三種情況:

  1. timeout==NULL,永遠等待。當所指定的文件描述符中的一個已準備好或捕捉到一個信號則返回。如果捕捉到一個信號,則select返回-1,errno設置爲EINTR。
  2. timeout->tv_sec==0 && timeout->tv_usec==0,完全不等待。
  3. timeout->tv_sec!=0 || timeout->tv_usec != 0,等待指定的秒數和微妙數。當指定的描述符之一已準備好,或當指定的時間已經超過時立即返回,超時時返回0。與第一種情況一樣,這種等待也可能被信號中斷。

中間的三個參數readfds、writefds和exceptfds是指向描述符集的指針。這三個描述符集說明了我們關心的可讀、可寫或處於異常條件的各個描述符。描述符集使用fd_set類型表示。
對fd_set類型可以進行的處理是:分配一個這種類型的變量;將這種類型的一個變量值賦予同類型的另一個變量;或對於這種類型的變量使用下列四個函數。

#include <sys/select.h>
// 判斷fd是否在set中
int  FD_ISSET(int fd, fd_set *set);
    返回值:若fd在描述符集中則返回非0值,否則返回0// 將fd添加到set集合中
void FD_SET(int fd, fd_set *set);
// 將fd從set中移除
void FD_CLR(int fd, fd_set *set);
// 將set清零
void FD_ZERO(fd_set *set);

中間參數中的任意一個或全部都可以是空指針,這表示對應的狀態並不關心。如果三個指針都是空指針,那麼select提供了比sleep更精確的定時器。

select的第一個參數nfds需要傳入“最大的描述符加1”。在三個描述符集中,找出最大的描述符值,然後加1。

select的變體pselect:

#include <sys/select.h>
/**
* @param  nfds      最大描述符加1
* @param  readfds  讀描述符集
* @param  writefds  寫描述符集
* @param  exceptfds 異常描述符集
* @param  timeout  超時時間
* @param  sigmask  信號屏蔽字
* @return          準備就緒的描述符個數,若超時則返回0,失敗返回-1
*/
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, const struct timespec *timeout,
                  const sigset_t *sigmask);

除了一下幾點,pselect和select相同:

  • select的超時值用timeval定義,pselect的超時值使用timespec定義。timespec使用秒和納秒錶示超時值。pselect的超時值爲const。
  • pselect可以指定信號屏蔽字。在調用pselect時原子的安裝信號屏蔽字,在返回時,恢復以前的信號屏蔽字。

poll

poll函數類似於select,poll的定義如下:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout)

與select不同,poll不是每個狀態(可讀性、可寫性和異常狀態)構造一個描述符集,而是統一的放在pollfd數組中,每個數組元素指定一個描述符以及對其關心的狀態。

struct pollfd {
    int fd; // 描述符
    short events; // 對該描述符的哪些事件感興趣
    short revents; // 該描述符哪些事件發生了
};

nfds說明數組fds的長度。
events可以設置爲下面表格中的值。函數返回時,內核設置revents成員,說明在該描述符上發生了哪些事件。
這裏寫圖片描述
表14-6中,頭四行測試可讀性,接着三行測試可寫性,最後三行測試異常狀態。最後三行是由內核在返回時設置的。即使在events中沒有指定這三個值,如果相應條件發生了,在revents中仍然會設置它們。
當一個描述符被掛斷(POLLHUP)後,就不能再寫該描述符。但是仍可從該描述符讀取數據。
poll的最後一個參數說明我們願意等待的時間,與select一樣,有三種情況:
1. timeout == -1,永遠等待。當所指定的描述符中有一個準備好或則捕捉到一個信號時返回。
2. timeout == 0,不等待。測試所有描述符並立即返回。
3. timeout > 0,等待timeout毫秒。當指定的描述符之一準備好,或指定的時間超時時立即返回。超時返回0。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章