非阻塞IO
存在阻塞式的原因:
常见的阻塞:wait、pause、sleep等函数;read或write某些文件时
阻塞式的好处:提升OS整体性能
非阻塞
非阻塞的IO访问:O_NONBLOCK和fcntl
阻塞式IO的困境
程序中读取键盘
int main(void)
{
char buf[100];
//读取键盘,就是标准输入,stdin编号0
memset(buf, 0, sizeof(buf));
printf("before read.\n");
read(0, buf, 2);
printf("读出的内容是: [%s].\n", buf);
return 0;
}
程序中读取鼠标
鼠标的设备文件在/dev/input/里面
int main(void)
{
//读取鼠标
int fd = -1;
char buf[200];
fd = open("/dev/input/mouse0", O_RDONLY);
if(fd < 0)
{
perror("open");
return -1;
}
memset(buf, 0, sizeof(buf));
printf("before read.\n");
read(fd, buf, 50);
printf("读出的内容是: [%s].\n", buf);
return 0;
}
程序中同时读取键盘和鼠标
问题:只能按照程序设定的方式先读键盘或者鼠标
并发式IO的解决方法
非阻塞式IO
程序中非阻塞式读取键盘
int main(void)
{
char buf[100];
int flag = -1;//将0号文件描述符变成非阻塞式的
flag = fcntl(0, F_GETFL);//获取原来flag
flag |= O_NONBLOCK; //添加非阻塞属性
fcntl(0, F_SETFL, flag);//更新flag
//0成为非阻塞式//读取键盘,就是标准输入,stdin编号0
memset(buf, 0, sizeof(buf));
printf("before read.\n");
read(0, buf, 2);
printf("读出的内容是: [%s].\n", buf);
return 0;
}
程序中非阻塞式读取鼠标
int main(void)
{
//读取鼠标
int fd = -1;
char buf[200];
fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
if(fd < 0)
{
perror("open");
return -1;
}
memset(buf, 0, sizeof(buf));
printf("before read.\n");
read(fd, buf, 50);
printf("读出的内容是: [%s].\n", buf);
return 0;
}
程序中同时读取键盘和鼠标
int main(void)
{
//读取鼠标
int fd = -1;
int flag = -1;
char buf[200];
int ret = 0;
fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
if(fd < 0)
{
perror("open");
return -1;
}
//将0号文件描述符变成非阻塞式的
flag = fcntl(0, F_GETFL);//获取原来flag
flag |= O_NONBLOCK; //添加非阻塞属性
fcntl(0, F_SETFL, flag);//更新flag
//0成为非阻塞式
while(1)
{
//读鼠标
memset(buf, 0, sizeof(buf));
//printf("before 鼠标 read.\n");
ret = read(fd, buf, 50);
if(ret > 0)
{
printf("鼠标读出的内容是: [%s].\n", buf);
}//读键盘
memset(buf, 0, sizeof(buf));
//printf("before 键盘 read.\n");
ret = read(0, buf, 2);
if(ret > 0)
{
printf("键盘读出的内容是: [%s].\n", buf) ;
}}
return 0;
}
多路复用IO(IO multiplexing)
多路非阻塞式IO
selec函数t和poll函数(本身阻塞式)
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
nfds = 最大的文件描述符+1, fd_set表示文件描述符的集合
slect
int main(void)
{
//读取鼠标
int fd = -1,ret = 0;
char buf[200];
fd_set myset;
struct timeval tm;
fd = open("/dev/input/mouse0", O_RDONLY);
if(fd < 0)
{
perror("open");
return -1;
}//当前有两个fd,一个是fd一个是0
//处理myset
FD_ZERO(&myset);
FD_SET(fd, &myset);
FD_SET(0, &myset);
tm.tv_sec = 10;
tm.tv_usec = 0;
ret = select(fd+1, &myset, NULL, NULL, &tm);
if(ret < 0)
{
perror("select:.\n");
return -1;
}else if(ret == 0)
{
printf("超时!");
}else
{
//等到了一路IO,监测是哪个IO到了并处理
if(FD_ISSET(0, &myset))
{
//处理键盘
memset(buf, 0, sizeof(buf));
read(0, buf, 2);
printf("读出的内容是: [%s].\n", buf);}
if(FD_ISSET(fd, &myset))
{
//处理鼠标
memset(buf, 0, sizeof(buf));
read(fd, buf, 50);
printf("读出的内容是: [%s].\n", buf);}
}return 0;
}
poll
int main(void)
{
//读取鼠标
int fd = -1,ret = 0;
char buf[200];
struct pollfd myfds[2]={0};
fd = open("/dev/input/mouse0", O_RDONLY);
if(fd < 0)
{
perror("open");
return -1;
}
//初始化myfds数组
myfds[0].fd = 0; //键盘
myfds[0].events = POLLIN; //等待读操作
myfds[1].fd = fd; //鼠标
myfds[1].events = POLLIN; //等待读操作ret = poll(myfds, fd+1, 10000);
if(ret < 0)
{
perror("poll:.\n");
return -1;
}else if(ret == 0)
{
printf("超时!");
}else
{
//等到了一路IO,监测是哪个IO到了并处理
for(int i = 0; i < 2; i++)
{
if(myfds[i].events == myfds[i].revents)
{
memset(buf, 0, sizeof(buf));
read(0, buf, 2);
printf("读出的内容是: [%s].\n", buf);
}
}
}return 0;
}
外部阻塞式(本身阻塞式),内部非阻塞式自动轮询多路阻塞式IO
异步IO
异步IO就是OS用软件实现的一套中断响应系统
异步IO的工作方法:进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到SIGIO信号从而执行绑定的处理函数去处理异步事件
函数:
fcntl (F_GETFL、F_SETFL、O_ASYNC、F_SETOWN )
signal或者sigaction(SIGIO)
示例
int mousefd = -1;
//绑定SIGIO信号,处理异步通知事件
void func (int sig)
{
char buf[200];
if(sig != SIGIO)
{
return;
}
memset(buf, 0, sizeof(buf));
read(mousefd, buf, 50);
printf("鼠标读出的内容是: [%s].\n", buf);
}
int main(void)
{
//读取鼠标
int flag = -1;
char buf[200];
mousefd = open("/dev/input/mouse0", O_RDONLY);
if(mousefd < 0)
{
perror("open");
return -1;
}
//鼠标文件描述符设置为可以接收异步IO
flag = fcntl(mousefd, F_GETFL);
flag |= O_ASYNC;
fcntl(mousefd, F_SETFL, flag);
//把异步IO事件的接收进程设置为当前进程
fcntl(mousefd, F_SETOWN, getpid());
//注册当前进程的SIGIO捕获函数
signal(SIGIO, func);//读键盘
while(1)
{
memset(buf, 0, sizeof(buf));
read(0, buf, 50);
printf("键盘读出的内容是: [%s].\n", buf);
}
return 0;
}
存储映射IO
mmap函数(内存映射)
LCD显示和IPC之共享内存
特点:1、共享不是复制,减少内存操作。2、处理大文件时效率高,小文件性价比低