112-IO 多路复用

1. 问题提出

假设有这样一段程序:

// fd1, fd2, fd3 分别是以只读的方式打开的三个不同有名管道的描述符(a.fifo, b.fifo, c.fifo)

while(1) {
  n = read(fd1, buf, 64);
  write(STDOUT_FILENO, buf, n);

  n = read(fd2, buf, 64);
  write(STDOUT_FILENO, buf, n);

  n = read(fd3, buf, 64);
  write(STDOUT_FILENO, buf, n);
}

回忆前面学习过的《有名管道》,只要写端没有写入数据,读端就永远阻塞。

这意味着上面的程序将会在三个 read 中任何一个或多个发生阻塞。不妨假设在 fd1 上永远阻塞,那么即使 fd2 和 fd3 上有数据到来,也没有机会执行。

多进程和多线程的确可以解决上面的问题,但是代价就是得为进程同步或线程同步做更多的处理。除此之外还有异步 IO 也可以搞定,这个暂时不提。

还有一种方案是使用非阻塞 IO,这种方案实际上之前的文章有讲过,参考 《阻塞与非阻塞IO》

能不能有一种更好办法,只要我们事先知道上面三个描述符 fd1, fd2, fd3 中有一个可以读不产生阻塞,我们就能顺利解决它:

while(1) {
  if (fd1 有数据) {
    n = read(fd1, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
  if (fd2 有数据) {
    n = read(fd2, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
  if (fd3 有数据) {
    n = read(fd3, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
}

既然这里提出来了,那就说明这种技术肯定是存在的——IO 多路复用

2. IO 多路复用

这里一定要把“IO复用”的原文贴出来,I/O Multiplexing. 第一,不至于造成误解;第二,也许从英文的角度来描述,更加贴切。

在国内,大多数情况都将 multiplex 翻译成复用,所谓的复用,表面意思是“重复利用”?学过通信的同学立即想到时分复用、频分复用、码分复用这些概念。

但是这些看起来是“重复利用”吗?似乎是同时使用不同的通道而已。比方说频分复用,应该是同时使用 1GHz、2GHz 等等不同频率的波段而已。而复用的含义,应该是指将同一个信道划分成很多条通道,所有信号的传输共用一个信道,但是属于不同通道。

所以,I/O Multiplexing 应该翻译成 IO 多路传输可能更加确切。类比一下,就是一条 IO 通道,被划分成了多个 IO 通道,允许同时进行多个 IO 读写。

这里回到第 1 节提出的问题上,三个描述符 fd1, fd2, fd3 可以认为是三个不同的 IO 通道,如何将其合并成一条大的“总线”,大的 IO 通道?

不妨假设这个大 IO 通道是一个数组 or 集合,或者是其它什么容器,它保存了这三个描述符,假设它就是大数组 fds[3] 吧。

接下来,同时“监听”这个“大描述符”,假设 IO 复用技术为我们提供了一个函数叫 select,它应该被翻译成查询比较合适,前面的代码现在像下面这样:

while(1) {
  fds[0] = fd1;
  fds[1] = fd2;
  fds[2] = fd3;

  // 只要三个描述符上都没有数据可读,select 就阻塞; 
  // 如果有某些描述符上有数据,fds 对应的内容就保留,否则就改成 -1.
  select(fds);

  if (fds[0] == fd1) {
    n = read(fd1, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
  if (fds[1] == fd2) {
    n = read(fd2, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
  if (fds[2] = fd3) {
    n = read(fd3, buf, 64);
    write(STDOUT_FILENO, buf, n);
  }
}

问题似乎都已经顺利解决,还有什么不满意的地方吗?这里没有多进程,多线程,也没有使用非阻塞 IO,应该是相当令人满意了。先休息休息,好好体会,I/O Multiplexing 是做什么的吧。

3. 总结

  • 理解第 1 节中提出的问题的目的
  • 理解 IO 多路复用的含义
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值