---非阻塞式IO
阻塞式读取键盘和鼠标:
// 读取鼠标 int fd = -1; char buf[200]; fd = open("/dev/input/mouse1", 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); // 读键盘 memset(buf, 0, sizeof(buf)); printf("before 键盘 read.\n"); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); return 0;
实现非阻塞IO访问:O_NONBLOCK和fcntl
int fcntl(int fd, int cmd, ... /* arg */ );
F_GETFL (void)
Get the file access mode and the file status flags; arg is ignored.
F_SETFL (int)
Set the file status flags to the value specified by arg. File access mode
(O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL,
O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this command can change only the
O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
属性:
O_NONBLOCK //非阻塞
O_ASYNC //接收异步IO
int fd = -1; int flag = -1; char buf[200]; int ret = -1; fd = open("/dev/input/mouse1", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open:"); return -1; } // 把0号文件描述符(stdin)变成非阻塞式的 flag = fcntl(0, F_GETFL); // 先获取原来的flag flag |= O_NONBLOCK; // 添加非阻塞属性 fcntl(0, F_SETFL, flag); // 更新flag // 这3步之后,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, 5); if (ret > 0) { printf("键盘读出的内容是:[%s].\n", buf); } }
---多路复用IO
select和poll
外部阻塞式,内部非阻塞式自动轮询多路阻塞式IO
---select函数介绍
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); //nfds:多路阻塞式IO中最大的文件描述符+1//*readfds:要读的IO//*writefds:要写的IO//*exceptfds:出现错误的IO//*timeout:超时时间,在超时时间内,有IO激活函数,则立刻返回,没有IO激活,则在到达超时时间时返回//struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
//返回值:0-超时返回 >0-返回的是IO的返回路数 -1-返回错误
select的几个宏函数:
void FD_CLR(int fd, fd_set *set); //将fd从set里面拿出去 clearO(∩_∩)O~ int FD_ISSET(int fd, fd_set *set); //判断fd有没有被置位,返回值是正的,说明这个fd的IO发生了,负的就没有发生 void FD_SET(int fd, fd_set *set); //将fd添加进set里面去 void FD_ZERO(fd_set *set); //将所有的fd_set全部清除出去
代码实践:用select函数实现同时读取键盘鼠标
int fd = -1, ret = -1; char buf[200]; fd_set myset; struct timeval tm; fd = open("/dev/input/mouse1", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } // 当前有2个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: "); return -1; } else if (ret == 0) { printf("超时了\n"); } else { // 等到了一路IO,然后去监测到底是哪个IO到了,处理之 if (FD_ISSET(0, &myset)) { // 这里处理键盘 memset(buf, 0, sizeof(buf)); read(0, buf, 5); 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 poll(struct pollfd *fds, nfds_t nfds, int timeout);
//使用前必须先设置
struct
pollfd
*
fds
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ //是内核设置的 };
events常用宏: POLLIN There is data to read. //FD要读 POLLOUT Writing now will not block.//FD要写
如果有事件发生,要判断是哪个IO发生的,就去判断每个IO的
events和revents是否相等
,若相等就说明此IO发生
返回值和select一样;
代码实践:用poll函数实现同时读取键盘鼠标
// 读取鼠标 int fd = -1, ret = -1; char buf[200]; struct pollfd myfds[2] = {0}; fd = open("/dev/input/mouse1", O_RDONLY); if (fd < 0) { perror("open:"); return -1; } // 初始化我们的pollfd 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: "); return -1; } else if (ret == 0) { printf("超时了\n"); } else { // 等到了一路IO,然后去监测到底是哪个IO到了,处理之 if (myfds[0].events == myfds[0].revents) { // 这里处理键盘 memset(buf, 0, sizeof(buf)); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } if (myfds[1].events == myfds[1].revents) { // 这里处理鼠标 memset(buf, 0, sizeof(buf)); read(fd, buf, 50); printf("鼠标读出的内容是:[%s].\n", buf); } } return 0;
---异步通知(异步IO)
异步IO的工作方法是:我们当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到一个SIGIO信号从而执行绑定的处理函数去处理这个异步事件。
3.6.6.2、涉及的函数:
(1)fcntl(F_GETFL、F_SETFL、O_ASYNC、F_SETOWN)
(2)signal或者sigaction(SIGIO)
3.6.3.代码实践
int mousefd = -1;// 绑定到SIGIO信号,在函数内处理异步通知事件void func(int sig){ char buf[200] = {0}; if (sig != SIGIO) return; read(mousefd, buf, 50); printf("鼠标读出的内容是:[%s].\n", buf);}int main(void){ // 读取鼠标 char buf[200]; int flag = -1; mousefd = open("/dev/input/mouse1", O_RDONLY); if (mousefd < 0) { perror("open:"); return -1; } // 把鼠标的文件描述符设置为可以接受异步IO flag = fcntl(mousefd, F_GETFL); flag |= O_ASYNC; //接受异步IO fcntl(mousefd, F_SETFL, flag); // 把异步IO事件的接收进程设置为当前进程 fcntl(mousefd, F_SETOWN, getpid()); // 注册当前进程的SIGIO信号捕获函数 signal(SIGIO, func); // 读键盘 while (1) { memset(buf, 0, sizeof(buf)); //printf("before 键盘 read.\n"); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } return 0;}
---存储映射IO
mmap函数
LCD显示和IPC之共享内存
存储映射IO的特点
(1)共享而不是复制,减少内存操作
(2)处理大文件时效率高,小文件不划算
转载请注明原文地址: https://ju.6miu.com/read-669977.html