非阻塞IO是相对于传统的阻塞IO而言的。函数
咱们首先须要搞清楚,什么是阻塞IO。APUE指出,系统调用分为两类,低速系统调用和其余,其中低速系统调用是可能会使进程永远阻塞的一类系统调用。可是与磁盘IO有关的系统调用是个例外。spa
咱们以read和write为例,read函数读取stdin,若是是阻塞IO,那么:code
若是咱们不输入数据,那么read函数会一直阻塞,一直到咱们输入数据为止。blog
若是是非阻塞IO,那么:进程
若是存在数据,读取而后返回,若是没有输入,那么直接返回-1,errno置为EAGAINstring
咱们用write作一个实验:it
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/wait.h> #include <errno.h> #include <signal.h> char buf[500000]; int main(int argc, const char *argv[]) { int ntowrite, nwrite; ntowrite = read(STDIN_FILENO, buf, sizeof buf); fprintf(stderr, "read %d bytes\n", ntowrite); activate_nonblock(STDOUT_FILENO, O_NONBLOCK); char *ptr = buf; int nleft = ntowrite; //剩余的字节数 while(nleft > 0) { errno = 0; nwrite = write(STDOUT_FILENO, ptr, nleft); fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno); if(nwrite > 0) { ptr += nwrite; nleft -= nwrite; } } deactivate_nonblock(STDOUT_FILENO); return 0; }
该程序向标准输出写入500000个字节。io
若是使用: class
./test < test.mkv > temp.file
那么输出结果为:test
read 500000 bytes
nwrite = 500000, errno = 0
由于磁盘IO的速度较快,因此一次就能够写入,下面咱们使用终端:
./test < test.mkv 2> stderr.txt
这行命令将500000的内容打印到屏幕上,同时将fprintf记录的信息经过标准错误流写入stderr.txt。
咱们查看stderr.txt文件:
read 500000 bytes nwrite = 12708, errno = 0 nwrite = -1, errno = 11 nwrite = -1, errno = 11 nwrite = -1, errno = 11 nwrite = -1, errno = 11 nwrite = -1, errno = 11 nwrite = -1, errno = 11 nwrite = 11687, errno = 0 nwrite = -1, errno = 11
…………………………………………..
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = 1786, errno = 0
采用命令统计了一下,总计read次数为15247次,其中返回-1次数为15203次,说明成功读取次数为44次。
上面例子中,这种采用非阻塞IO的方式称为“轮询”,显然这是一种低效的方式,非阻塞IO一般与IO复用模型结合使用。
另外,将fd设置为阻塞和非阻塞的函数代码以下:
void activate_nonblock(int fd) { int ret; int flags = fcntl(fd, F_GETFL); if (flags == -1) ERR_EXIT("fcntl"); flags |= O_NONBLOCK; ret = fcntl(fd, F_SETFL, flags); if (ret == -1) ERR_EXIT("fcntl"); } void deactivate_nonblock(int fd) { int ret; int flags = fcntl(fd, F_GETFL); if (flags == -1) ERR_EXIT("fcntl"); flags &= ~O_NONBLOCK; ret = fcntl(fd, F_SETFL, flags); if (ret == -1) ERR_EXIT("fcntl"); }
未完待续。