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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章