select() - Unix、Linux 系统调用
Tutorials Point


  Unix 初学者指南
  Unix Shell 编程
  高级 Unix
  Unix 有用参考
  Unix 有用资源
  精选阅读

版权所有 © 2014 tutorialspoint



  首页     参考     讨论论坛     关于 TP  

select() - Unix、Linux 系统调用


previous next AddThis Social Bookmark Button

广告

名称

select、pselect、FD_CLR、FD_ISSET、FD_SET、FD_ZERO - 同步 I/O 多路复用

语法

/* 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); void FD_ZERO(fd_set *set);

#define _XOPEN_SOURCE 600 #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 操作(例如,输入可能)。如果可以执行相应的 I/O 操作(例如,read(2))而不会阻塞,则文件描述符被认为已准备就绪。

select() 和 pselect() 的操作相同,但有三个区别

序号描述
(i)select() 使用一个 struct timeval(秒和微秒)类型的超时,而 pselect() 使用一个 struct timespec(秒和纳秒)类型的超时。
(ii) select() 可能会更新 timeout 参数以指示剩余时间。pselect() 不会更改此参数。
(iii) select() 没有 sigmask 参数,并且其行为类似于使用 NULL sigmask 调用 pselect()。

监视三组独立的文件描述符。列在 readfds 中的文件描述符将被监视,以查看是否有字符可供读取(更准确地说,查看读取是否不会阻塞;特别是,文件描述符在文件结束时也已准备就绪),列在 writefds 中的文件描述符将被监视,以查看写入是否不会阻塞,列在 exceptfds 中的文件描述符将被监视,以查看异常。退出时,集合会在原地修改以指示哪些文件描述符实际上更改了状态。如果没有任何文件描述符要监视相应的事件类别,则三组文件描述符中的每一组都可以指定为 NULL。

提供了四个宏来操作集合。

  • FD_ZERO() 清空集合。

  • FD_SET() 和

  • FD_CLR() 分别将给定的文件描述符添加到集合中和从集合中移除。

  • FD_ISSET() 测试文件描述符是否为集合的一部分;

这在 select() 返回后很有用。

nfds 是三组集合中编号最高的描述符加 1。

timeoutselect() 返回之前经过时间的上限。它可以为零,导致 select() 立即返回。(这对于轮询很有用。)如果 timeout 为 NULL(无超时),则 select() 可以无限期阻塞。

sigmask 是指向信号掩码的指针(请参阅 sigprocmask(2));如果它不为 NULL,则 pselect() 首先用 sigmask 指向的信号掩码替换当前信号掩码,然后执行“select”函数,然后恢复原始信号掩码。

除了 timeout 参数精度上的差异外,以下 pselect() 调用

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

等效于原子地执行以下调用

sigset_t origmask;

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

需要 pselect() 的原因是,如果要等待信号或文件描述符准备就绪,则需要原子测试以防止竞争条件。(假设信号处理程序设置全局标志并返回。然后,在调用 select() 之前测试此全局标志可能会无限期挂起,如果信号恰好在测试后但调用之前到达。相反,pselect() 允许首先阻塞信号,处理已到达的信号,然后使用所需的 sigmask 调用 pselect(),从而避免了竞争条件。)

超时

涉及的时间结构在 <sys/time.h> 中定义,如下所示

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

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

(但是,请参见下面关于 POSIX.1-2001 版本的内容。)一些代码使用所有三组都为空、n 为零以及非 NULL timeout 调用 select() 作为以亚秒精度休眠的相当便携的方式。

在 Linux 上,select() 会修改 timeout 以反映未休眠的时间;大多数其他实现不会这样做。(POSIX.1-2001 允许这两种行为。)这会导致在将读取 timeout 的 Linux 代码移植到其他操作系统时出现问题,以及在将代码移植到 Linux 时出现问题,这些代码在循环中对多个 select() 重复使用 struct timeval 而无需重新初始化它。在 select() 返回后,认为 timeout 未定义。

返回值

如果成功,select() 和 pselect() 将返回三个返回的描述符集中包含的文件描述符的数量(即,在 readfdswritefdsexceptfds 中设置的位的总数),如果在发生任何有趣的事情之前超时过期,则该数量可能为零。如果出错,则返回 -1,并且 errno 被相应地设置;集合和 timeout 变得未定义,因此在错误后不要依赖其内容。

错误

标签描述
EBADF 在一组中给出了无效的文件描述符。(可能是已关闭的文件描述符,或已发生错误的文件描述符。)
EINTR 捕获到信号。
EINVAL nfds 为负或 timeout 中包含的值无效。
ENOMEM 无法为内部表分配内存。

示例

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
    fd_set rfds;
    struct timeval tv;
    int retval;

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    /* Wait up to five seconds. */
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    retval = select(1, &rfds, NULL, NULL, &tv);
    /* Don’t rely on the value of tv now! */

    if (retval == -1)
        perror("select()");
    else if (retval)
        printf("Data is available now.\n");
        /* FD_ISSET(0, &rfds) will be true. */
    else
        printf("No data within five seconds.\n");
    return 0;
}

符合标准

select() 符合 POSIX.1-2001 和 4.4BSD

pselect() 在 POSIX.1g 和 POSIX.1-2001 中定义。



previous next Printer Friendly

广告


  

广告



广告