read() 系统调用会复制数据而不是传递引用
Posted
技术标签:
【中文标题】read() 系统调用会复制数据而不是传递引用【英文标题】:read() system call does a copy of data instead of passing the reference 【发布时间】:2011-04-19 10:54:04 【问题描述】:read()
系统调用导致内核复制数据,而不是通过引用传递缓冲区。我在一次采访中被问到了这样做的原因。我能想到的最好的是:
-
为了避免跨多个进程同时写入同一缓冲区。
如果用户级进程尝试访问映射到内核虚拟内存区域的缓冲区,则会导致段错误。
事实证明,面试官对这两个答案都不完全满意。如果有人能详细说明上述内容,我将不胜感激。
【问题讨论】:
【参考方案1】:零拷贝实现意味着用户级进程必须有权访问内核/驱动程序内部使用的缓冲区以进行读取。用户在使用完缓冲区后必须显式调用内核来释放缓冲区。
根据读取的设备类型,缓冲区可能不仅仅是一个内存区域。 (例如,某些设备可能要求缓冲区位于内存的特定区域中。或者它们只能支持在启动时向它们提供固定的内存区域。)在这种情况下,用户程序无法“释放这些缓冲区(以便设备可以向它们写入更多数据)可能会导致设备和/或其驱动程序停止正常运行,这是用户程序永远无法做到的。
【讨论】:
请注意,例如最近内核实现了“拼接”支持,这意味着熔丝驱动程序现在存在零复制路径【参考方案2】:缓冲区由调用者指定,因此获取数据的唯一方法是复制它们。由于历史原因,API 的定义方式也是如此。
请注意,上述两点对于替代方案mmap
来说没有问题,它确实通过引用传递缓冲区(写入缓冲区而不是写入文件,因此您无法就地处理数据,而read
的许多用户就是这样做的)。
【讨论】:
使用MAP_PRIVATE
,写入地图不会修改文件。【参考方案3】:
我可能已经准备好反驳面试官的说法了。 read()
调用中的缓冲区由用户进程提供,因此来自用户地址空间。它也不能保证以任何特定方式与页框对齐。这使得直接在缓冲区中执行 IO 所需的操作变得很棘手,即。将缓冲区映射到设备驱动程序的地址空间或将其连接到 DMA。但是,在有限的情况下,这是可能的。
我似乎记得 Mac OS X 用于在地址空间之间复制数据的 BSD 子系统在这方面进行了优化,尽管我可能完全弄错了。
【讨论】:
以上是关于read() 系统调用会复制数据而不是传递引用的主要内容,如果未能解决你的问题,请参考以下文章
如果 Swift 通过值而不是引用传递,为啥我可以通过将 UIView 传递给函数来在 Swift 中操作 UIView 的属性? [复制]