在Linux应用编程中的并发式IO的三种解决方案是:

(1) 多路非阻塞式IO

(2) 多路复用

(3) 异步IO

以下代码将以操作鼠标和键盘为实例来演示。

1. 多路非阻塞式IO

多路非阻塞式IO访问,主要是添加O_NONBLOCK标志和fcntl()函数。

代码示例:

 /*
* 并发式IO的解决方案1:多路非阻塞式IO处理键盘和鼠标同时读取
*/ #include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #define MOUSEPATH "/dev/input/mouse1" int main(void)
{
int fd = -;
int ret = -;
int flag = -;
char buf[] = {}; fd = open(MOUSEPATH, O_RDONLY | O_NONBLOCK);
if (fd < )
{
perror("open");
_exit(-);
} // 把0的文件描述符变成非阻塞式的
flag = fcntl(, F_GETFD); // 获取stdin原来的flag
flag |= O_NONBLOCK; // 给stdin原来的flag添加非阻塞式属性
fcntl(, F_SETFL, flag); // 更新flag while ()
{
// 读鼠标
memset(buf, , sizeof(buf));
ret = read(fd, buf, ); if (ret > )
{
printf("鼠标读出的内容是:[%s]\n", buf);
} // 读键盘
memset(buf, , sizeof(buf));
ret = read(, buf, );
if (ret > )
{
printf("键盘读出的内容是:[%s]\n", buf);
}
} return ;
}

2. IO多路复用

(1) 多路非阻塞式IO

(2) select() 和 poll() 函数

(3) 外部式阻塞,内部非阻塞式自动轮询多路阻塞式IO

代码示例:

select() 函数实现:

 /*
* 并发式IO的解决方案2:多路复用select()函数处理
*/ #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <stdlib.h> #define MOUSEPATH "/dev/input/mouse1" int main(void)
{
int fd = -, ret = -;
char buf[] = {};
fd_set myset;
struct timeval tmv; fd = open(MOUSEPATH, O_RDONLY);
if (- == fd)
{
perror("open");
_exit(-);
} // 处理myset
FD_ZERO(&myset); // 清零
FD_SET(fd, &myset); // 加载鼠标的文件描述符到myset集合中
FD_SET(, &myset); // struct timeval *timeout 超时处理
tmv.tv_sec = ;
tmv.tv_usec = ; // 原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
ret = select(fd+, &myset, NULL, NULL, &tmv); // fd+1 这里是最大的fd加1 nfds是从0开始的
if (ret < )
{
perror("select");
_exit(-);
}
else if (ret == )
{
printf("Timeout.\n");
exit();
}
else
{
/* 等到了一路IO,然后去监测哪个IO到了就处理哪个IO */
if ( FD_ISSET(fd, &myset) )
{
// 这里处理鼠标
memset(buf, , sizeof(buf));
read(fd, buf, );
printf("鼠标读出的内容是:[%s]\n", buf);
} if ( FD_ISSET(, &myset) )
{
// 这里处理键盘
memset(buf, , sizeof(buf));
read(, buf, );
printf("键盘读出的内容是:[%s]\n", buf);
}
} return ;
}

poll() 函数实现:

 /*
* 并发式IO的解决方案2:多路复用poll()函数处理
*/ #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h> #define MOUSEPATH "/dev/input/mouse1"
#define IO_MULTIPLEXING 2
#define MAXBUF 1024
#define MILLISECOND 1000 int main(void)
{
int fd = -, ret = -, i = ;
char buf[MAXBUF] = {};
struct pollfd pfd[IO_MULTIPLEXING] = {}; fd = open(MOUSEPATH, O_RDONLY);
if (- == fd)
{
perror("open");
_exit(-);
} // 初始化 pollfd
pfd[].fd = ; // 键盘
pfd[].events = POLLIN; // 等待读操作 pfd[].fd = fd; // 键盘
pfd[].events = POLLIN; // 等待读操作 // 原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
ret = poll(pfd, fd+, * MILLISECOND); // fd+1 这里是最大的fd加1 nfds是从0开始的
if (ret < )
{
perror("poll");
_exit(-);
}
else if (ret == )
{
printf("Timeout.\n");
exit();
}
else
{
/* 等到了一路IO,然后去监测哪个IO到了就处理哪个IO */
for (i = ; i < IO_MULTIPLEXING; i++)
{
// 处理键盘和鼠标
if ( pfd[i].events == pfd[i].revents )
{
memset(buf, , sizeof(buf));
read(pfd[i].fd, buf, MAXBUF);
printf("Content:[%s].\n", buf);
}
}
} close(fd); return ;
}

3. 异步IO

(1) 异步IO:就是操作系统用软件实现的一套中断响应系统

(2) 工作方法:进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数)

(3) 涉及函数:fcntl(F_GETFL, F_SETFL, O_ASYNC, F_SETOWN), signal(), sigaction()函数

代码示例:

 /*
* 并发式IO的解决方案3:异步IO处理 signal or sigaction and fcntl
*/ #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h> #define MAXBUFF 1024
#define MOUSEPATH "/dev/input/mouse1" // 全局变理
int mousefd = -; // 定义signal的函数指针
typedef void (*sighandler_t)(int); // 函数声明
void func(int sig); int main(void)
{
int flag = -;
char buf[MAXBUFF];
sighandler_t ret = (sighandler_t)-; // 操作鼠标文件
mousefd = open(MOUSEPATH, O_RDONLY);
if ( mousefd < )
{
perror("open");
_exit(-);
} // 把鼠标的文件描述符设置为可以接受异步IO
flag = fcntl(mousefd, F_GETFL);
flag |= O_ASYNC;
fcntl(mousefd, F_SETFL, flag); // 把异步IO事件的接收进程设置为当前进程
fcntl(mousefd, F_SETOWN, getpid()); // 注册当前进程的SIGIO信号捕获函数
ret = signal(SIGIO, func);
if (SIG_ERR == ret)
{
perror("signal");
_exit(-);
} // 操作键盘
while ()
{
memset(buf, , sizeof(buf));
read(, buf, MAXBUFF);
printf("键盘读取的内容是:[%s].\n", buf);
} return ;
} // 绑定到SIGIO信号,在函数内处理异步通知事件
void func(int sig)
{
char buf[MAXBUFF] = {}; if ( sig != SIGIO )
return; read(mousefd, buf, MAXBUFF);
printf("鼠标读取的内容是:[%s].\n", buf);
}

并发式IO的解决方案:多路非阻塞式IO、多路复用、异步IO的更多相关文章

  1. 阻塞、非阻塞、同步、异步IO

    阻塞.非阻塞.同步.异步IO http://www.cnblogs.com/yunxitalk/p/9031306.html 介绍 在谈及网络IO的时候总避不开阻塞.非阻塞.同步.异步.IO多路复用. ...

  2. Java IO(3)非阻塞式输入输出(NIO)

    在上篇<Java IO(2)阻塞式输入输出(BIO)>的末尾谈到了什么是阻塞式输入输出,通过Socket编程对其有了大致了解.现在再重新回顾梳理一下,对于只有一个“客户端”和一个“服务器端 ...

  3. 一文读懂阻塞、非阻塞、同步、异步IO

    介绍 在谈及网络IO的时候总避不开阻塞.非阻塞.同步.异步.IO多路复用.select.poll.epoll等这几个词语.在面试的时候也会被经常问到这几个的区别.本文就来讲一下这几个词语的含义.区别以 ...

  4. Linux NIO 系列(03) 非阻塞式 IO

    目录 一.非阻塞式 IO 附:非阻塞式 IO 编程 Linux NIO 系列(03) 非阻塞式 IO Netty 系列目录(https://www.cnblogs.com/binarylei/p/10 ...

  5. 简述linux同步与异步、阻塞与非阻塞概念以及五种IO模型

    1.概念剖析 相信很多从事linux后台开发工作的都接触过同步&异步.阻塞&非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞.异步就是非阻塞,下面我们先剖析下这几个概念分 ...

  6. 网络IO之阻塞、非阻塞、同步、异步总结

    网络IO之阻塞.非阻塞.同步.异步总结 1.前言 在网络编程中,阻塞.非阻塞.同步.异步经常被提到.unix网络编程第一卷第六章专门讨论五种不同的IO模型,Stevens讲的非常详细,我记得去年看第一 ...

  7. 阻塞式和非阻塞式IO

    有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...

  8. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

  9. 磁盘IO的性能指标 阻塞与非阻塞、同步与异步 I/O模型

    磁盘IO的性能指标 - 蝈蝈俊 - 博客园https://www.cnblogs.com/ghj1976/p/5611648.html 阻塞与非阻塞.同步与异步 I/O模型 - 蝈蝈俊.net - C ...

随机推荐

  1. Embeding Python & Extending Python with FFPython

    Introduction ffpython is a C++ lib, which is to simplify tasks that embed Python and extend Python. ...

  2. (笔记)Linux内核学习(七)之内核同步机制和实现方式

    一 原子操作 指令以原子的方式执行——执行过程不被打断. 1 原子整数操作 原子操作函数接收的操作数类型——atomic_t //定义 atomic_t v;//初始化 atomic_t u = AT ...

  3. Android中AutoCompleteTextView的使用

    1.http://blog.csdn.net/FX_SKY/article/details/9326129 此博客讲解了auto组件如何使用baseAdapter来扩展功能,推荐参照此博客写demo ...

  4. Promise 使用心得

        this.testPromise=function(){         return new Promise(function(resolve,reject){             co ...

  5. Volley 实现原理解析(转)

    Volley 实现原理解析 转自:http://blog.csdn.net/fengqiaoyebo2008/article/details/42963915 1. 功能介绍 1.1. Volley ...

  6. 给MySQL官方提交的bug report备忘

    1.  Bug #72215 When LOCK_plugin conflicts very much, one uninstall-audit-plugin operation crash  htt ...

  7. python watchdog

    监视文件变更 #!/usr/bin/python # -*- coding:UTF-8 -*- import time from watchdog.observers import Observer ...

  8. Linux下添加硬盘,分区,格式化详解

    2005-10-17 在我们添加硬盘前,首先要了解linux系统下对硬盘和分区的命名方法. 在Linux下对IDE的设备是以hd命名的,第一个ide设备是hda,第二个是hdb.依此类推 我们一般主板 ...

  9. ASP.NET 网站支持多语言

    ASP.NET网站支持多语言 (本地资源文件和全局资源文件的调用及需注意的地方总结)   一.   本地资源文件(App_LocalResources): ①.     本地资源的生成及调用 1.本地 ...

  10. [0x01 用Python讲解数据结构与算法] 关于数据结构和算法还有编程

    忍耐和坚持虽是痛苦的事情,但却能渐渐地为你带来好处. ——奥维德 一.学习目标 · 回顾在计算机科学.编程和问题解决过程中的基本知识: · 理解“抽象”在问题解决过程中的重要作用: · 理解并实现抽象 ...