📄 00000012.htm
字号:
<HTML><HEAD> <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人: SuperSB (孤鹰), 信区: Linux <BR>标 题: [转载]unix环境高级编程-12 <BR>发信站: BBS 水木清华站 (Wed Mar 15 14:30:35 2000) <BR> <BR> <BR> <BR> <BR>发信人: taosm (128+64-->cool), 信区: unix <BR>标 题: unix环境高级编程--第12章 高级I/O <BR>发信站: 西十八BBS (Sat Mar 11 13:50:56 2000), 转信 <BR> <BR> <BR>第十二章 高级I/O <BR>12.1 引言 <BR>本章内容包括:非阻塞I/O、记录锁、系统V流机制、I/O多路转接(select和poll <BR>函数)、readv和writev函数,以及存储映照I/O(mmap)。在第十四章、十五章中 <BR>说明的进程间通信,以及以后各章中的很多实例都要使用本章所述的概念和函数。 <BR> <BR>12.2 非阻塞I/O <BR>在10.5节中曾将系统调用分成两类:低速系统调用和其它。低速系统调用是可能会 <BR>使进程永远阻塞的一类系统调用: <BR>l 如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道,终端设备 <BR>和网络设备)。 <BR>l 如果数据不能立即被接受,则写这些同样的文件也会使调用者永远阻塞。 <BR>l 在某些条件发生之前,打开文件会被阻塞(例如打开一个终端设备可能需等待到 <BR>一个连接的调制解调器应答;又例如若以只写方式打开FIFO,那么在没有其它进程 <BR>已用读方式打开该FIFO时也要等待)。 <BR>l 对已经加上了强制性记录锁的文件进行读、写。 <BR>l 某些ioctl操作。 <BR>l 某些进程间通信函数(第十四章)。 <BR>虽然读、写磁盘文件会使调用在短暂时间内阻塞,但并不能将它们视为"低速"。 <BR>非阻塞I/O使我们可以调用不会永远阻塞的I/O操作,例如open,read和write。如果 <BR>这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去。 <BR>对于一个给定的描述符有两种方法对其指定非阻塞I/O: <BR>1. 如果是调用open以获得该描述符,则可指定O_NONBLOCK标志(3.3节)。 <BR>2. 对于已经打开的一个描述符,则可调用fcntl,对其打开O_NONBOCK文件状态标 <BR>志(3.13节)。在程序3.5中的函数可用来为一个描述符打开任一文件状态标志。 <BR> <BR>早期的系统V版本使用标志O_NDELAY指定非阻塞方式。在这些版本中,如果无数据 <BR>可读,则read返回值0。而Unix又常将read的返回值0解释为文件结束,两者有所混 <BR>淆。PISIX.1则提供了一个非阻塞标志,它的名字和语义都与O_NDELAY不同。PISI <BR>X.1要求,对于一个非阻塞的描述符如果无数据可读,则read返回-1,并且errno被 <BR>设置为EAGAIN。SVR4支持较老的O_NDELAY和POSIX.1的O_NONBLOCK,但在本书的实 <BR>例中只使用POSIX.1规定的特征。O_NDELAY是为了向后兼容性,不应在新应用程序 <BR>中使用。 <BR>4.3BSD为fcntl提供FNDELAY标志,其语义也稍有区别。它不只影响该描述符的文件 <BR>状态标志,它将终端设备或套接口的标志更改成非阻塞的,因此影响了终端或套接 <BR>口的所有用户,不只是影响共享同一文件表项的用户(4.3BSD非阻塞I/O只对终端 <BR>和套接口起作用)。如果对一个非阻塞描述符的操作不能无阻塞地完成,那么4.3 <BR>BSD返回EWOULDBLOCK。4.3+BSD提供POSIX.1的O_NONBLOCK标志,但其语义却类似于 <BR>4.3BSD的FNDELAY。非阻塞I/O通常用来处理终端设备或网络连接,而这些设备通常 <BR>一次由一个进程使用。这就意味着BSD语义的更改通常不会影响我们。出错返回EW <BR>OULDBLOCK而不是POSIX.1的EAGAIN,这造成了可移植性问题,我们必须处理这一问 <BR>题。4.3+BSD也支持FIFO,非阻塞I/O也对FIFO起作用。 <BR>实例 <BR>程序12.1是一个非阻塞I/O的实例,它从标准输入读100,000字节,并试图将它们 <BR>写到标准输出上。该程序先将标准输出设置为非阻塞的,然后用for循环进行输出 <BR>,每次写的结果都在标准出错上打印。函数ctl-f1类似于程序3.5中的set-f1,但 <BR>与set-f1的功能相反,它清除1个或多个标志位。 <BR>#include <sys/types.h> <BR>#include <errno.h> <BR>#include <fcntl.h> <BR>#include "ourhdr.h" <BR>char buf[100000]; <BR>int <BR>main(void) <BR>{ <BR> int ntowrite, nwrite; <BR> char *ptr; <BR> ntowrite = read(STDIN_FILENO, buf, sizeof(buf)); <BR> fprintf(stderr, "read %d bytes\n", ntowrite); <BR> set_fl(STDOUT_FILENO, O_NONBLOCK); /* set nonblocking */ <BR> for (ptr = buf; ntowrite > 0; ) { <BR> errno = 0; <BR> nwrite = write(STDOUT_FILENO, ptr, ntowrite); <BR> fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno); <BR> if (nwrite > 0) { <BR> ptr += nwrite; <BR> ntowrite -= nwrite; <BR> } <BR> } <BR> clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */ <BR> exit(0); <BR>} <BR>程序12.1 长的非阻塞写 <BR>若标准输出是普通文件,则可以期望write只执行一次。 <BR>$ ls -l /etc/termcap <BR> 印文件长度 <BR>-rw-rw-r-1 root 133439 Oct 11 1990 /etc/termcap <BR>$a.out < /etc/termcap >temp.file 先试一普 <BR> 文件 <BR>read 100000 bytes <BR>nwrite-100000, errno=0 一次写 <BR>$ls -l temp.file <BR> 验输出文件长度 <BR>-rw-rw-r-1 stevens 100000 Nev 21 16:27 temp.file <BR>但是,若标准输出是终端,则可期望write有时会返回一个数字,有时则出错返回 <BR>。下面是在一个系统上运行程序12.1的结果: <BR>$ a.out < /etc/termcap 2>stderr.out 向终端输出 <BR> <BR> 大量输出至终端 <BR>$ cat stderr.out <BR>read 100000 bytes <BR>nwrite=8192, errno=0 <BR>nwrite=8192, errno=0 <BR>nwrite=-1, errno=11 <BR>庵执
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -