(APUE点滴记录) 高级I/O之非阻塞I/O

来源:互联网 发布:好域名的七大特点 编辑:程序博客网 时间:2024/05/18 00:12

2013-03-30 wcdj

低速系统调用是可能会使进程永远阻塞的一类系统调用,而非阻塞I/O使调用open, read和write这样的I/O操作,并使这些操作不会永远阻塞,如果这种操作不能完成,则调用立即出错返回,表示该操作若继续执行将阻塞。

对于一个给定的描述符有2种方法对其指定为非阻塞I/O:
(1) 如果调用open获得描述符,则可指定O_NONBLOCK标志;
(2) 对于已经打开的一个描述符,则可调用fcntl,由该函数打开O_NONBLOCK文件状态标志;

测试用例:
从STDIN_FILENO标准输入读500K的buffer,设置STDOUT_FILENO为非阻塞I/O,然后将buffer写到标准输出上。
测试1:输出到普通文件
nonblock_write < buffer.txt > out.txt
测试2:输出到终端,并将标准错误信息输出到stderr.out文件
nonblock_write < buffer.txt 2>stderr.out
此时,write有时返回小于500k的一个数字,有时返回出错,errno显示系统调用返回的错误,EAGAIN在Linux上是11,在Max OS X上是35。通过统计,程序发出了数千个write调用,但是只有几百个是真正输出数据的,其余的则出错返回,这种形式的循环称为“轮询”,在多用户系统上它浪费了CPU时间。(对此问题的解决方法是:使用I/O多路转接select和poll函数,以节省CPU的时间)

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <time.h>// test buffer is 500Mchar buf[500000000];// flags are file status flags to turn onvoidset_fl(int fd, int flags){int val;if ((val = fcntl(fd, F_GETFL, 0)) < 0){printf("fcntl F_GETFL error\n");exit(1);}// turn on flagsval |= flags;if (fcntl(fd, F_SETFL, val) < 0){printf("fcntl F_SETFL error\n");exit(1);}}// flags are file status flags to turn offvoidclr_fl(int fd, int flags){int val;if ((val = fcntl(fd, F_GETFL, 0)) < 0){printf("fcntl F_GETFL error\n");exit(1);}// turn off flagsval &= ~flags;if (fcntl(fd, F_SETFL, val) < 0){printf("fcntl F_SETFL error\n");exit(1);}}int main(int argv, char **argc){int ntowrite, nwrite;char *ptr;ntowrite = read(STDIN_FILENO, buf, sizeof(buf));fprintf(stderr, "read %d bytes\n", ntowrite);// set nonblockingset_fl(STDOUT_FILENO, O_NONBLOCK);// time begtime_t beg = time(NULL);ptr = buf;while (ntowrite > 0){errno = 0;// it will not block here!nwrite = write(STDOUT_FILENO, ptr, ntowrite);fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno);if (nwrite > 0){ptr += nwrite;ntowrite -= nwrite;}}// time end time_t end = time(NULL);fprintf(stderr, "used time: %lds\n", end - beg);// clear nonblockingclr_fl(STDOUT_FILENO, O_NONBLOCK);return 0;}



原创粉丝点击