Linux - select()

在 Linux 編程時遇到問題最方便的就是應用 man 命令, 每一個知識點都講解得很詳細, 所以遇到問題最佳的辦法是先 man 讀懂之後再去網絡中搜資料。
爲方便閱讀,此文翻譯了 man select 的內容。

函數原型及相關說明

/* According to POSIX.1-2001 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);`enter code here`
void FD_ZERO(fd_set *set);

#include <sys/select.h>

int pselect(int nfds, fd_set *readfds, fd_set *writefds,
            fd_set *exceptfds, const struct timespec *timeout,
            const sigset_t *sigmask);

描述
select()pselect() 令程序可以監聽多個文件描述符,等待直到有描述符變成 I/O 操作的 ready 狀態。
select()pselect() 只有三點區別:
select()timeout 結構體爲 struct timeval(包含秒和毫秒)而 pselect 使用的 timeout 結構體爲struct timespec(包含秒和納秒)。
select() 可能會更新timeout參數來指示還剩多長時間,pselect() 則不會修改 timeout 參數。
select() 沒有 sigmask 參數與 pselect()sigmask 參數爲NULL時功能完全相同。

監聽的三個獨立文件描述符集:
readfds 監聽文件描述符是否可讀,不監聽可以傳入 NULL
writefds 監聽文件描述符是否可寫 ,不監聽可以傳入 NULL
exceptfds 監聽文件描述符是否有異常,不監聽可以傳入 NULL

提供了四個宏定義來操作描述符集:
FD_ZERO() - 清空描述符集
FD_SET() - 添加文件描述符到描述符集
FD_CLR() - 從描述符集中移除文件描述符
FD_ISSET() - 測試一個文件描述符是否在當前描述符集中 - 用於 select 返回後

nfdsselect 監控的三個描述符中的最大值加1

timeout 指定 select 的等待阻塞時間,如果 timeout 結構體指定的時間爲0則 select 會立即返回,如果 timeoutNULLselect 會一直等待直到有描述符狀態被改變。

sigmask 是一個信號掩碼的指針,如果指針不爲空,則 pselect 先屏蔽 sigmask 指定的信號,然後執行 select 函數,最後再恢復sigmask指定的信號。

ready = pselect(nfds, &readfds, &writefds, &exceptfds, timeout, &sigmask);

相當於

sigset_t origmask;

pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
pthread_sigmask(SIG_SETMASK, &origmask, NULL);

在需要避免競爭的狀態下使用 pselecet

超時結構體

struct timeval {
   long    tv_sec;         /* seconds */
   long    tv_usec;        /* microseconds */
};

struct timespec {
   long    tv_sec;         /* seconds */
   long    tv_nsec;        /* nanoseconds */
};

注:每次調用 select 之前都應該重新初始化 timeval 結構體變量。

返回值
成功時返回包含三種描述符集的文件描述符的個數(已經準備好的描述符個數)
超時時返回 0
錯誤時返回 -1,並且將描述符集清空。

錯誤
EBADF — 指定的需要檢測的文件描述符集不合法(一個已經關閉的描述符,或者一個出現錯誤的描述符)
EINTR — 信號被捕捉,詳見 signal
EINVALnfds 是負數或者 timeout 中的值不合法
ENOMEM — 不能爲內部表分配內存

注意
文件描述 fd 必須小於 FD_SETSIZE 否則可能會導致未知錯誤。
select 監聽的文件描述符在其他線程中被關閉時,會導致未知的結果。在一些 Unix 系統中會導致 select() 函數不阻塞立即返回,並且指定這個文件描述符是 ready 狀態。在 Linux 將不會對 select 造成影響。因此,在程序設計時應考慮這種現象以防止留下隱患。

Linux 提供了使用用例詳見:
man select_tut

發佈了37 篇原創文章 · 獲贊 24 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章