00. 目录

文章目录

  • 00. 目录
  • 01. 概述
  • 02. select函数
  • 03. select程序示例
  • 04. select优缺点
  • 05. 附录

01. 概述

I/O 多路复用技术是为了解决进程或线程阻塞到某个 I/O 系统调用而出现的技术,使进程不阻塞于某个特定的 I/O 系统调用。

select(),poll(),epoll()都是I/O多路复用的机制。I/O多路复用通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪,就是这个文件描述符进行读写操作之前),能够通知程序进行相应的读写操作。但select(),poll(),epoll()本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

与多线程和多进程相比,I/O 多路复用的最大优势是系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程。

02. select函数

#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
功能:监视并等待多个文件描述符的属性变化(可读、可写或错误异常)。select()函数监视的文件描述符分 3 类,分别是writefds、readfds、和 exceptfds。调用后 select() 函数会阻塞,直到有描述符就绪(有数据可读、可写、或者有错误异常),或者超时( timeout 指定等待时间),函数才返回。当 select()函数返回后,可以通过遍历 fdset,来找到就绪的描述符。参数:nfds: 要监视的文件描述符的范围,一般取监视的描述符数的最大值+1,如这里写 10, 这样的话,描述符 0,1, 2 …… 9 都会被监视,在 Linux 上最大值一般为1024。readfd: 监视的可读描述符集合,只要有文件描述符即将进行读操作,这个文件描述符就存储到这。writefds: 监视的可写描述符集合。exceptfds: 监视的错误异常描述符集合。timeout: 超时时间,它告知内核等待所指定描述字中的任何一个就绪可花多少时间。其 timeval 结构用于指定这段时间的秒数和微秒数。
返回值:成功:就绪描述符的数目,超时返回 0,出错:-1timeout参数有三种可能:1)永远等待下去:仅在有一个描述字准备好 I/O 时才返回。为此,把该参数设置为空指针 NULL。2)等待固定时间:在指定的固定时间( timeval 结构中指定的秒数和微秒数)内,在有一个描述字准备好 I/O 时返回,如果时间到了,就算没有文件描述符发生变化,这个函数会返回 0。3)根本不等待(不阻塞):检查描述字后立即返回,这称为轮询。为此,struct timeval变量的时间值指定为 0 秒 0 微秒,文件描述符属性无变化返回 0,有变化返回准备好的描述符数量。struct timeval {long    tv_sec;         /* seconds */long    tv_usec;        /* microseconds */};中间的三个参数 readfds、writefds 和 exceptfds 指定我们要让内核监测读、写和异常条件的描述字。如果不需要使用某一个的条件,就可以把它设为空指针( NULL )。集合fd_set 中存放的是文件描述符,可通过以下四个宏进行设置://将一个给定的文件描述符从集合中删除void FD_CLR(int fd, fd_set *set);// 检查集合中指定的文件描述符是否可以读写int  FD_ISSET(int fd, fd_set *set);//将一个给定的文件描述符加入集合之中void FD_SET(int fd, fd_set *set);//清空集合void FD_ZERO(fd_set *set);

03. select程序示例

我们写这么一个例子,同时循环读取标准输入的内容,读取有名管道的内容,默认的情况下,标准输入没有内容,read()时会阻塞,同样的,有名管道如果没有内容,read()也会阻塞,我们如何实现循环读取这两者的内容呢?最简单的方法是,开两个线程,一个线程循环读标准输入的内容,一个线程循环读有名管道的内容。而在这里,我们通过 select() 函数实现这个功能:

#include <sys/select.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char *argv[])
{fd_set rfds;struct timeval tv;int ret;int fd;ret = mkfifo("test_fifo", 0666); // 创建有名管道if(ret != 0){perror("mkfifo:");}fd = open("test_fifo", O_RDWR); // 读写方式打开管道if(fd < 0){perror("open fifo");return -1;}ret = 0;while(1){// 这部分内容,要放在while(1)里面FD_ZERO(&rfds);        // 清空FD_SET(0, &rfds);   // 标准输入描述符 0 加入集合FD_SET(fd, &rfds);  // 有名管道描述符 fd 加入集合// 超时设置tv.tv_sec = 1;tv.tv_usec = 0;// 监视并等待多个文件(标准输入,有名管道)描述符的属性变化(是否可读)// 没有属性变化,这个函数会阻塞,直到有变化才往下执行,这里没有设置超时// FD_SETSIZE 为 <sys/select.h> 的宏定义,值为 1024ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);//ret = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);if(ret == -1){ // 出错perror("select()");}else if(ret > 0){ // 准备就绪的文件描述符char buf[100] = {0};if( FD_ISSET(0, &rfds) ){ // 标准输入read(0, buf, sizeof(buf));printf("stdin buf = %s\n", buf);}else if( FD_ISSET(fd, &rfds) ){ // 有名管道read(fd, buf, sizeof(buf));printf("fifo buf = %s\n", buf);}}else if(0 == ret){ // 超时printf("time out\n");}}return 0;
}

下面为上面例子的往有名管道写内容的示例代码:

#include <sys/select.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char *argv[])
{//select_demo(8);fd_set rfds;struct timeval tv;int ret;int fd;ret = mkfifo("test_fifo", 0666); // 创建有名管道if(ret != 0){perror("mkfifo:");}fd = open("test_fifo", O_RDWR); // 读写方式打开管道if(fd < 0){perror("open fifo");return -1;}while(1){char *str = "this is for test";write(fd, str, strlen(str)); // 往管道里写内容printf("after write to fifo\n");sleep(5);}return 0;
}

04. select优缺点

select优点:

select()目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。

select的缺点

1)每次调用 select(),都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大,同时每次调用 select() 都需要在内核遍历传递进来的所有 fd,这个开销在 fd 很多时也很大。

2)单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

05. 附录

【Linux系统编程】IO多路复用之select相关推荐

  1. Linux网络编程(IO多路复用)

    网络编程 1 操作系统 1.1 用户空间与内核空间 1.2 进程切换 1.3 进程的阻塞 1.4 文件描述符fd 2 IO多路复用 2.1 阻塞IO 2.1.1 多线程/多进程 2.1.2 线程池 2 ...

  2. linux io多路复用详解,Linux系统中IO多路复用

    文章目录 1 什么是IO多路复用 1.1 阻塞IO模型 1.2 非阻塞IO模型 1.3 IO复用模型 1.4 信号驱动IO模型 1.5 异步IO模型 2 IO多路复用,epoll 1 什么是IO多路复 ...

  3. Linux系统编程——I/O多路复用select、poll、epoll

    参考:https://segmentfault.com/a/1190000003063859 Linux下的I/O复用与epoll详解:https://www.cnblogs.com/lojunren ...

  4. Linux系统编程 / triggerhappy 源码分析(3.select 的应用)

    哈喽,我是老吴,继续记录我的学习心得. 一.进步的滞后性 我们期望进步是线性: 每一个人付出一些努力后,都希望它有立竿见影的效果. 现实是: 做出努力后,结果的显现往往滞后. 只有在几个月或几年后,我 ...

  5. Linux系统编程25:基础IO之亲自实现一个动静态库

    本文接:Linux系统编程24:基础IO之在Linux下深刻理解C语言中的动静态库以及头文件和库的关系 文章目录 A:说明 B:实现静态库 C:实现动态库 A:说明 前面说过,库其实就是头文件和和.a ...

  6. linux原子过程,linux系统编程:IO读写过程的原子性操作实验

    所谓原子性操作指的是:内核保证某系统调用中的所有步骤(操作)作为独立操作而一次性加以执行,其间不会被其他进程或线程所中断. 举个通俗点的例子:你和女朋友OOXX的时候,突然来了个电话,势必会打断你们高 ...

  7. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】

    linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...

  8. Linux系统编程之文件IO

    Linux系统编程之文件IO 文件IO第一天 一.标准IO基本概念 1.1c语言函数 (c库函数) 调用实现某一个功能,(API) 1.2系统调用:内核中的程序接口,应用程序和硬件设备之间的中间层 1 ...

  9. linux系统io编程,Linux系统编程(1) —— 文件IO

    本文主要对Linux系统中文件I/O的基本操作进行说明. 在Linux系统编程中,对文件进行处理的流程,通常是: 打开文件 读写文件 关闭文件 Linux内核对每一个进程维护一个打开的文件列表, 该文 ...

  10. 【Linux】一步一步学Linux系统编程教程汇总(暂时暂停更新......)

    00. 目录 文章目录 00. 目录 01. 概述和标准 02. 文件操作 03. 进程概念 04. 进程间通信 05. 多线程 06. 信号 07. 同步与互斥 08. 高级IO 09. 其它 10 ...

最新文章

  1. 在S/4HANA扩展字段的Available Fields列表里,看不到自己创建的扩展字段该怎么办
  2. linux 关掉蓝牙自动,如何在Ubuntu 14.04中默认关闭蓝牙,蓝牙
  3. 微型计算机主板上安装的主要部件有,微型计算机的主板上安装的主要部件有()....
  4. 后置增强this advice advises no methods_增强消防意识 提高消防能力 重庆天一新城小学积极参加消防技能比赛活动...
  5. Python-copy()与deepcopy()之间的主要区别
  6. MFC双缓冲解决图象闪烁
  7. PHPMailer 报错:SMTP ERROR: Password command failed: 535 Login Fail
  8. 系统动力学建模代做,vensim建模代做,流图建模,不确定分析。
  9. Pandas query 的用法, df.query
  10. matlab仿真动画,用matlab制作简单仿真动画
  11. JMeter Linux下执行测试
  12. Mysql服务器安装步骤
  13. 轻松理解LTE网规网优FAQ基本概念
  14. 巨噬细胞膜包裹PLGA纳米粒HCPT-MCNP/MCF-7细胞膜包覆PLGA纳米球共载姜黄素和二氢卟吩e6的研究
  15. 怎样与团队成员沟通,从而提高团队的执行力?
  16. 医药之家:医疗器械龙头企业排名变动,11家中国企业入选全球百强!
  17. 以json格式输出 bro(zeek)日志
  18. Java项目:洗浴中心管理系统(java+SSM+JSP+jQuery+javascript+Mysql)
  19. 网管必备-CMD命令
  20. o2o项目部署前,阿里云的申请与环境搭建

热门文章

  1. 使用反射代替不断添加的if-else来实现代码的可扩展性
  2. Redis快速入门:安装、配置和操作
  3. 算法——海量数据(5%)
  4. nginx匹配规则_Nginx系列之server_name定义与匹配规则
  5. moment 时间格式化
  6. P4774 [NOI2018]屠龙勇士
  7. SharePoint2010 修改模板页在网页中间显示网站内容
  8. exists改写SQL,使其走正确的执行计划
  9. Jquery Mobile 百度地图 Demo
  10. Unity3D Input按键系统