在 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
返回後
nfds
是 select
監控的三個描述符中的最大值加1
timeout
指定 select
的等待阻塞時間,如果 timeout
結構體指定的時間爲0則 select
會立即返回,如果 timeout
爲 NULL
則 select
會一直等待直到有描述符狀態被改變。
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
EINVAL
— nfds
是負數或者 timeout
中的值不合法
ENOMEM
— 不能爲內部表分配內存
注意
文件描述 fd
必須小於 FD_SETSIZE
否則可能會導致未知錯誤。
當 select
監聽的文件描述符在其他線程中被關閉時,會導致未知的結果。在一些 Unix 系統中會導致 select()
函數不阻塞立即返回,並且指定這個文件描述符是 ready
狀態。在 Linux 將不會對 select
造成影響。因此,在程序設計時應考慮這種現象以防止留下隱患。
Linux 提供了使用用例詳見:
man select_tut