读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。
阻塞读终端
#include <unistd.h>
#include <stdio.h> #include <stdlib.h>
int main(void) { char buf[10]; int n; n = read(STDIN_FILENO, buf, 10);//从标准输入读取字符到buf里面 if (n < 0)
{ printf("read error"); exit(1); } write(STDOUT_FILENO, buf, n);//把buf的数据写到标准输出上(终端)
return 0; }
目前我们学过的可能引起阻塞的设备只有终端,所以我们用终端来做这个实验。程序开始执行时在0、1、2文件描述符上自动打开的文件就是终端,但是没有O_NONBLOCK标志。所以读标准输入是阻塞的。我们可以重新打开一遍设备文件/dev/tty(表示当前终端),在打开时指定O_NONBLOCK标志。
非阻塞读终端
#include <unistd.h> #include <fcntl.h>
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #define MSG_TRY "test again\n" int main(void) { char buf[10]; int fd, n; fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);//用只读和非阻塞的方式打开tty if(fd<0)
{
printf("open error\n"); exit(1); } tryagain: n = read(fd, buf, 10); if (n < 0)
{
/*
如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。以read为例,如果设备暂时没有数据可读就返回-1,同时置errno为EWOULDBLOCK(或者EAGAIN,这两个宏定义的值相同)
*/
if (errno == EAGAIN)
{ sleep(1); write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY)); goto tryagain; } perror("read /dev/tty");
exit(1); } write(STDOUT_FILENO, buf, n); close(fd); return 0; }
