在程序中经常会需要同时处理多路输入输出流,采用阻塞的方法会无法达成想要的效果,而采用不阻塞的方法时需要对多个输入输出信号不停的轮询会太浪费cpu时间。如果采用线程或进程的方法将产生线程或进程之间的同步与通信问题这会使程序变得复杂。解决问题相对较好的解决方法就是利用select函数。
selec函数原型:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
参数:
nfds:监测的最大文件描述个数
readfds: 读事件集合
writefds: 写事件集合,传NULL表示不关心
exceptfds:异常事件集合;
timeout:超时检测 1
如果不做超时检测:传 NULL
返回值:
<0 出错
>0 表示有事件产生;
如果设置了超时检测时间:&tv
select返回值:
<0 出错
>0 表示有事件产生;
==0 表示超时时间已到;
结构体:
struct timeval
{
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
相关函数:
void FD_CLR(int fd, fd_set *set);//将fd从表中清除
int FD_ISSET(int fd, fd_set *set);//判断fd是否在表中
void FD_SET(int fd, fd_set *set);//将fd添加到表中
void FD_ZERO(fd_set *set);//清空表
select函数的特点:
1. 一个进程最多只能监听1024个文件描述符 。
2. select被唤醒之后需要重新轮询一遍驱动的poll函数,效率较低。
3. select每次会清空表,每次都需要拷贝用户空间的表到内核空间,效率较低。
利用select函数实现对键鼠的信号检测:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
int main(int argc, char const *argv[])
{
//打开鼠标设备
int fd = open("/dev/input/mouse0", O_RDONLY);//在终端利用sudo cat /dev/input/mouse0
语句检测自己的鼠标位置
if (fd < 0)
{
perror("open mouse err.");
return -1;
}
//select 实现同时响应终端输入和鼠标输入
//1.创建表
fd_set readfds,tempfds;
//清空表
FD_ZERO(&readfds);
//2.将关心的文件描述符添加到表中
FD_SET(fd,&readfds);
FD_SET(0,&readfds);
int maxfd=fd;
char buf[128];
int ret;
while(1)
{
//3.调用select函数检测事件
tempfds=readfds;
ret=select(maxfd+1,&tempfds,NULL,NULL,NULL);
if(ret < 0)
{
perror("select err.");
return -1;
}
//终端输入
if(FD_ISSET(0,&tempfds))
{
fgets(buf,sizeof(buf),stdin);
printf("key:%s\n",buf);
}
//鼠标输入
if(FD_ISSET(fd,&tempfds))
{
int ret=read(fd,buf,sizeof(buf));
printf("mouse:%s\n",buf);
}
}
close(fd);
return 0;
}