read()系统调用执行数据副本而不是传递引用

时间:2011-04-19 10:54:05

标签: c linux process ipc

read()系统调用导致内核复制数据,而不是通过引用传递缓冲区。我在接受采访时被问到了这个原因。我能想到的最好的是:

  1. 避免跨多个进程在同一缓冲区上进行并发写入。
  2. 如果用户级进程尝试访问映射到内核虚拟内存区域的缓冲区,则会导致段错误。
  3. 事实证明,面试官对这些答案中的任何一个都不满意。如果有人能详细说明上述情况,我将不胜感激。

3 个答案:

答案 0 :(得分:3)

零拷贝实现意味着必须允许用户级进程访问内核/驱动程序内部使用的缓冲区以进行读取。用户必须对内核进行显式调用,以便在完成缓冲后释放缓冲区。

根据要读取的设备类型,缓冲区可能不仅仅是内存区域。 (例如,某些设备可能要求缓冲区位于特定的内存区域。或者它们只能支持在启动时写入固定的内存区域。)在这种情况下,用户程序无法“免费的“那些缓冲区(以便设备可以向它们写入更多数据)可能导致设备和/或其驱动程序停止正常运行,这是用户程序永远无法做到的。

答案 1 :(得分:1)

缓冲区由调用者指定,因此获取数据的唯一方法是复制它们。并且API由于历史原因而被定义为它。

注意,上面的两点对于替代mmap没有问题,它通过引用传递缓冲区(并写入它而不是写入文件,因此您无法处理数据在适当的位置,虽然read的许多用户都这样做了。

答案 2 :(得分:0)

我可能已经准备好对采访者的主张提出质疑。 read()调用中的缓冲区由用户进程提供,因此来自用户地址空间。它也不能保证在页面框架方面以任何特定方式对齐。这使得执行IO直接进入缓冲区所需的操作变得棘手。将缓冲区映射到设备驱动程序的地址空间或将其连接到DMA。但是,在有限的情况下,这可能是可能的。

我似乎记得Mac OS X用于在地址空间之间复制数据的BSD子系统在这方面有优化,尽管我可能完全错了。