阻塞、非阻塞IO
原创
©著作权归作者所有:来自51CTO博客作者tennysonsky的原创作品,请联系作者获取转载授权,否则将追究法律责任
阻塞与非阻塞是对于文件而言的,而不是指read、write等的属性。
阻塞IO
应用程序调用IO函数,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,一直等待数据准备好了,从内核拷贝到用户空间,IO函数返回成功指示。

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。一般网络、终端设备IO都是阻塞I/O。
如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。
示例代码:
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
char buf[1024] = {0};
printf("读数据前:\n");
read(0, buf, sizeof(buf)); //默认是阻塞的,从标准输入读取内容
printf("读取数据后:buf = %s\n", buf);
return 0;
}
运行结果:

非阻塞IO
我们把一个文件设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠,而是返回一个错误(EAGAIN)。
这样我们的I/O操作函数将不断的测试数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间,所有一般Web服务器都不使用这种I/O模型。

示例代码:
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
//以非阻塞方式打开当前终端
fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
if(fd < 0)
{
perror("open\n");
return -1;
}
char buf[1024];
while(1)
{
int n = read(fd, buf, sizeof(buf));
printf("n = %d, errno = %d, EAGAIN = %d\n", n, errno, EAGAIN);
sleep(1); //延时
if(n <= 0)
{
//如果为非阻塞,但是没有数据可读,此时全局变量 errno 被设置为 EAGAIN
if(errno == EAGAIN)
{
printf("没有数据可读\n");
}
else
{
perror("read");
break;
}
}
else
{//有数据
printf("buf = %s\n", buf);
break;
}
}
return 0;
}
运行结果:
