4-2 非阻塞型IO
1、阻塞方式是文件读写操作的默认方式,但应用程序员可通过使用O_NONBLOCK标志来人为的设置读写操作为非阻塞方式(该标志定义在<linux/fcntl.h>中,在打开文件时指定)。
2、如果设置了O_NONBLOCK标志,read和write的行为是不相同的。如果进程在没有数据就绪时,调用了read,或者在缓冲区没有空间时调用了write,系统只是简单地返回-EAGAIN,而不会阻塞进程。
3、调用进程显示的指明不想阻塞。
4、设置filp->flag|=O_NONBLOCK
//应用程序以非阻塞I/O的方式从串口驱动读取一字符
int fd;
char buf;
fd=open(“/dev/ttySAC0”,O_RDWR|O_NONBLOCK);//属性:可读可写,非阻塞方式访问。
……
while(read(fd,&buf,1)!=1) ; //串口上无输出也返回,所以要循环尝试读取串口
printf(“%c\n”,buf);
poll和select
5、poll和select都允许进程决定是否可以对一个或多个打开的文件做非阻塞的读取或写入。
6、这些调用也会阻塞进程,知道给定的文件描述符集中的任何一个可读取或写入。
7、常用于那些要使用多个输入或输出流而要不会阻塞于其中任何一个留的应用程序中。
8、select-在BSD Unix中引入
9、poll-由AT&T Unix System V引入
10、都是调用驱动程序的poll来实现。
unsigned int (*poll) (struct file* file,poll_table* wait);//返回可以立即执行操作的位掩码。
//<linux/poll.h>中声明,驱动程序不需要了解该结构的细节。
11、poll函数负责完成两个步骤:
11.1在一个或多个可只是poll状态变化的等待队列上调用poll_wait.
如果当前没有文件描述符可用来执行I/O,则内核将使进程在传递到该系统调用的所有文件描述符对应的等地啊队列上等待。
Void poll_wait(struct file*,wait_queue_head_t*,poll_table*);
//即:使用pool_wait将等待队列添加到poll_table中。
11.2返回一用来描述操作是否可以立即无阻塞执行的位掩码。
12、位掩码
12.1 <linux/poll.h>定义poll位掩码
12.2 POLLIN 设备可读
12.3 POLLRDNORM 数据可读(“normal” data is available for reading)
12.4 POLLOUT 设备可写
12.5 POLLWRNORM 数据可写 (”normal” data is available for writing)
12.6一般设备可读返回:POLLIN|POLLRDNORM
12.7一般设备可写返回:POLLIN|POLLWRNORM
13、select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程。
int select(int maxfd, fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
13.1 struct timeval
{
int tv_sec;//秒
int tv_usec;//微秒
};
13.2 maxfd:文件描述符范围,比待检测的最大文件描述符大1
13.3 readfds:被读监控的文件描述符集
13.4 writefds:被写监控的文件描述符集
13.5 exceptfds:被异常监控的文件描述符集
13.6 timeout:定时器。
13.7timeout取不同的值,该调用有不同的表现:
Timeout值为0,不管是否有文件满足要求,都立刻返回,无文件满足要求是返回0,有文件满足要求返回一个正值。
Timeout为NULL,select将阻塞进程,知道某个文件满足要求
Timeout值为正整数,就是等地啊的最长时间,即select在timeout时间内阻塞进程。
14、select调用返回时,返回值有如下情况:
正常情况下返回满足要求的文件描述符个数;
经过了timeout等待后热无文件满足要求,返回值为0;
如果select被某个信号中断,它将返回-1并设置errno为EINTR;
如果出错,返回-1并设置相应的errno.
15、select系统调用(使用方法)
15.1 将要监控的文件添加到文件描述符集
15.2 调用select开始监控
15.3 判断文件是否发生变化。
16、系统提供4个宏对描述符集进行操作:
FD_ZERO(fd_set* set);//清除一个文件描述符
FD_SET(int fd,fd_set *set);//将一个文件描述符加入文件描述符集中。
FD_CLR(int fd,fd_set* set);//将一个文件描述符从文件描述符集中清除。
FD_ISSET(int fd,fd_set* set);判断文件描述符是否被置位。
声明:本文非原创,整理自申嵌