IO监控:select

来源:互联网 发布:崔走召的网络电影 编辑:程序博客网 时间:2024/06/10 16:26

来自QQ群 Linux && 技术分享 311078264

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing 同步多路I/O技术。

1、
select() and pselect() allow a program to monitor multiple file descriptors,
waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possi‐ble).
A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2)) without blocking.

select() 和 pselect() 允许程序监控多个文件描述符,等待其中一个或者多个描述符中的某一类操作就绪,比如读或者写操作。
当一个描述符中可以不被阻塞的执行相应的操作就被视为处于就绪状态。

2、
Three independent sets of file descriptors are watched.
Those listed in readfds will be watched to see if characters become available for reading
(more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file),
those in writefds will be watched to see if a write will nonblock,
and those in exceptfds will be watched for exceptions.
On exit, the sets are modified in place to indicate which file descriptors actually changed status.
Each of the three file descriptor sets may be specified as NULL if no file descriptors are to be watched for the corresponding class of events.
文件描述符有三个独立的集合被系统监控,分别为读readfds、写writefds、异常exceptfds。
三个集合分别监控文件描述符是否可读,是否可写,是否有异常;
当执行完select()或者pselect()后,集合中的数据被适当的修改来表示文件描述符状态的变化;
当某个集合没有文件描述符需要被监控的时候就会被置为NULL。


3、
Four macros are provided to manipulate the sets.
FD_ZERO() clears a set.
FD_SET() and FD_CLR() respectively add and remove a given file descriptor from a set.
FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.
有四个宏来操作集合。
FD_ZERO() 用来清空集合。
FD_SET() 和 FD_CLR() 分别用来在集合中增减文件描述符。
FD_ISSET()用来测试某个文件描述符是否在集合中;当执行完select()之后这会非常有用。


/*=====================================*/

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nt pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);
这两个函数大多数功能是一样的,只是在超时和信号处理上有区别,具体区别请参看MAN手册。

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
nfds 是上面三个监控集合中数值最大的文件描述符再加上1.【(a<b ? b:a)+1】

readfds、writefds、exceptfds就是上面提到的三个集合,需要自己来定义变量;【fd_set readfds, writefds, exceptfds;】

timeout The timeout argument specifies the interval that select() should block waiting for a file descriptor to become ready.
If both fields of the timeval structure are zero, then select() returns immediately.(This is useful for polling.)
If timeout is NULL (no timeout), select() can block indefinitely.
timeout 指定了select() 应当阻塞等待文件描述符变为就绪状态的时间间隔,当文件描述符就绪的时候就会立刻返回。
当其值为NULL的时候,select等待的时间将会是不确定的。

sigmask is a pointer to a signal mask (see sigprocmask(2));
if it is not NULL, then pselect() first replaces the current signal mask by the one pointed to by sigmask,
then does the "select" function, and then restores the original signal mask.
sigmask 是用来说明屏蔽什么信号的变量,当它不为空pselect()会首先用给定的signal mask替换现有的signal mask,
然后执行和select一样的功能,最后恢复最初的signal mask。当其为NULL和select效果一样。


/**************/

timeout:
The time structures involved are defined in <sys/time.h> and look like

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

and

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

/******************************/
下面是man手册给出的例子:
运行后5s内在中断输出入字符并敲回车,就会显示Data is available now.并退出程序;
如果5s内不输入字符,就会显示No data within five seconds.并退出程序。

#include <stdio.h>
#include <stdlib.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");

exit(EXIT_SUCCESS);
}










0 0