首页 文章

带缓冲区的iostream的机制是什么?

提问于
浏览
3

首先,在cplusplus.com这里说every stream object has a associated std::streambuf
在c primer 5中它说:

每个输出流管理一个缓冲区,用于保存程序读取和写入的数据 . 例如,当执行以下代码时,请输入一个值:“;文字字符串可能会立即打印,或者操作系统可能会将数据存储在缓冲区中以便稍后打印 . 有几个条件会导致缓冲区被刷新 - 也就是说,要写入实际的输出设备或文件:程序正常完成,使用诸如endl之类的操纵器 .

根据我的理解,上面的上下文中的句子“操作系统可能存储数据 in a buffer (不在 the 缓冲区中)”意味着流对象和操作系统都使用自己的缓冲区,即进程地址空间中的一个,另一个在由OS管理的内核空间中 .

And here is my question,

  • 为什么每个进程/对象(如 cout )都管理自己的缓冲区?为什么不直接进行系统调用并将数据直接提供给OS缓冲区?

  • 此外,术语' flushed '是作用于对象缓冲区还是OS缓冲区?我猜 flushed 动作实际上引起了系统调用,并告诉操作系统立即将OS缓冲区中的数据放到屏幕上 .

1 回答

  • 1

    为什么每个进程/对象(如cout)都管理自己的缓冲区?为什么不直接进行系统调用并将数据直接提供给OS缓冲区?

    作为一个预答案,您可以始终重写流缓冲区以始终刷新到系统OS调用以进行输出(或输入) . 实际上,您的系统可能已经这样做了 - 它只取决于实现 . 这个系统只允许在iostreams库的级别进行缓冲,但并不一定要求它 .

    对于缓冲,逐字节发送或读取数据并不总是最有效的 . 在许多系统中如 coutcin 的情况下,操作系统可以更好地处理这种情况,但您可以调整iostream来处理读取套接字的输入和输出流(来自Internet连接的I / O) . 在套接字中,您可以通过Internet将单个包中的每个字符写入目标,但这可能会变得非常慢,具体取决于链接类型和链接的繁忙程度 . 当您读取套接字时,可以跨数据包拆分消息,因此您需要缓冲输入,直到您按下'critical mass' . 有可能在操作系统级别执行此缓冲,但我发现至少我可以获得更好的性能,如果我自己处理大部分缓冲(因为通常消息的大小在整个运行时间有很大的标准偏差) . 因此,iostreams中的缓冲是管理输入和输出以优化性能的有用方法,当您尝试同时处理来自多个连接的I / O时,这尤其有用 .

    但你不能总是假设操作系统会做正确的事情 . 我记得有一次我们使用这个FUSE模块,它允许我们在多个计算机节点上拥有一个分布式文件系统 . 在编写和阅读单个字符时,它有一个非常奇怪的问题 . 虽然读取或写入一长串单个字符在使用ext4系统的普通硬盘上最多需要几秒钟,但同样的操作在FUSE系统上需要几天时间(忽略了我们为什么这样做的原因) ) . 通过调试,我们发现挂起处于I / O级别,读取和写入单个字符会加剧此运行时问题 . 我们不得不重新编写代码来缓冲我们的读写操作 . 我们可以弄清楚的最好的是ext4上的操作系统做了自己的缓冲,但这个FUSE文件系统在读取和写入硬盘时没有做类似的缓冲 .

    在任何情况下,OS可以进行自己的缓冲,但是在许多情况下,这种缓冲不存在或最小 . 在iostream端缓冲可以帮助您的表现 .

    此外,术语'刷新'是作用于对象缓冲区还是操作系统缓冲区?我想刷新的动作实际上会唤醒系统调用并告诉操作系统立即将数据放入OS缓冲区中 .

    我相信大多数文本都会谈到C语言中标准I / O流的“刷新” . 您的程序可能无法直接控制操作系统如何处理其I / O.但总的来说,我认为操作系统和程序的I / O将与大多数系统同步 .

相关问题