一、阻塞IO
将系统调用分成两类:低速系统调用和其他
- 低速系统调用是可能会使进程永远阻塞的一类系统调用,包括下面:
二、非阻塞IO
- 概念:非阻塞I/O使我们可以调用不会永远阻塞的I/O操作,例如open,read和write。如果这种操作不能完成,则立即出错返回,表示该操作如继续执行将继续阻塞下去
对于给定的一个描述符,有两种方法对其指定非阻塞I/O:
- 如果是调用open以获得该描述符,则可指定O_NONBLOCK标志
- 对于已经打开的一个描述符,则可调用fcntl打开O_NONBLOCK文件状态标志
注意事项
三、非阻塞IO案例
- 是一个非阻塞I/O的实例,它从标准输入读500000字节,并试图将它们写到标准输出上。该程序先将标准输出设置为非阻塞的,然后用for循环进行输出,每次write的结果都在标准出错上打印
- 函数clr_fl清除文件描述符标志,它清除1个或多个标志位
#include<errno.h> #include<fcntl.h> #include<stdlib.h> #include<stdio.h> char buf[500000]; void clr_fl(int fd, int flags); void set_fl(int fd,int flags); int main(void) { int ntowrite, nwrite; char *ptr; ntowrite = read(0, buf, sizeof(buf));//从标准输入读取数据 fprintf(stderr, "read %d bytes\n", ntowrite); set_fl(1, O_NONBLOCK); //设置标准输出非阻塞 ptr = buf; while (ntowrite > 0) { errno = 0; nwrite = write(1, ptr, ntowrite);//将数据输出到标准输出上 fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno); if (nwrite > 0) { ptr += nwrite; ntowrite -= nwrite; } } clr_fl(2, O_NONBLOCK); //设置标准输出阻塞 exit(0); } void clr_fl(int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0)//先得到 perror("fcntl F_GETFL error"); val &= ~ flags; /* turn off flags */ if (fcntl(fd, F_SETFL, val) < 0)//再设置 perror("fcntl F_SETFL error"); } void set_fl(int fd, int flags) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0)//先得到 perror("fcntl F_GETFL error"); val |= flags; /* turn on flags */ if (fcntl(fd, F_SETFL, val) < 0)//再设置 perror("fcntl F_SETFL error"); }
运行结果:
- ①如果标准输出是普通文件,则可期望write只执行了一次
- ②如果标准输出是终端,则期望write有时小于50000的一个数字,有时返回错误