4

我知道默认情况下,C++ 支持的所有流 IO 都是缓冲的。

这意味着要输出的数据被放入缓冲区直到它满了,然后发送到输出设备,同样对于输入,一旦缓冲区为空,数据就会被读取......所有这些都是为了减少昂贵系统的数量可以最小化通话。

但是如何在行动中验证这种行为。我的意思是考虑以下代码

int main()
{
    cout << "Hello world\n";
    return 0
}

缓冲在这里出现在哪里?我知道发生了缓冲,但是如何解释呢?输出会立即在屏幕上看到,那么实际看到缓冲 I/O 的代码示例是什么?

4

3 回答 3

8

首先,并非所有 iostream 都被缓冲;缓冲由附加的 streambuf. 在filebuf( 由ifstreamand 使用ofstream) 的情况下,输入将尽可能多地读取,直到缓冲区的大小,并且输出将在溢出时刷新缓冲区,当显式刷新或关闭发生时,或者当对象被破坏时 (隐式调用close)。

的情况cout有点特殊,因为它永远不会被破坏也不会关闭。系统保证在flush被调用后至少会调用一次exit(当你从返回时会发生这种情况main)。这意味着从 main 返回之前的任何输出都将被刷新;如果你在cout静态对象的析构函数中使用,你仍然需要明确的刷新来确定。

也可以将tie输出流转换为输入流;cout 默认情况下绑定到cin。在这种情况下,任何从绑定流输入的尝试都会刷新输出。

通常的约定是只使用std::endl而不是简单地输出'\n'; std::endl输出 a'\n'然后刷新流。对于所有输出都迅速出现非常重要的流,unitbuf可以设置一个标志,这意味着流将在每个<<运算符结束时刷新。(std::cerr默认设置了这个。)

最后,如果你想看看缓冲的效果, sleep(10)在你的输出后面加上类似的东西。如果它立即出现输出,则它已被刷新;如果不是,则它已被缓冲,并且刷新隐式发生在sleep.

于 2012-07-09T10:12:55.143 回答
5

试试下面的程序。sleep(1)用于引入延迟(1 秒),我使用的是 linux,所以sleep对我有用。如果你不能让它工作,尝试其他方法来延迟这个程序(例如,简单的for循环)。如果您没有看到任何缓冲效果,您也可以尝试增加缓冲区大小(取消注释代码行)。

在我的操作系统(Linux 3.2.0)和编译器(g++ 4.6.3)上,这个程序打印“Portion1Portion2”,然后是“Portion3Portion4”,然后是“Portion5”。std::endl保证刷新缓冲区,但如您所见,换行符对我也适用。

#include <iostream>
#include <unistd.h>

using namespace std;

int main () {
    // Try uncommenting following lines to increase buffer size
    // char mybuf[1024];
    // cout.rdbuf()->pubsetbuf(mybuf, 1024);

    cout << "Portion1";
    sleep(1);
    cout << "Portion2\n";
    sleep(1);
    cout << "Portion3";
    sleep(1);
    cout << "Portion4" << endl;
    sleep(1);
    cout << "Portion5" << endl;
    sleep(1);
    cout << "Done!" << endl;

    return 0;
}
于 2012-07-09T10:03:49.360 回答
4

试试下面的代码:

int main()
{
    for( int i =0 ; i < 10; i ++ )
    {
        cout << i << " ";
        cerr << i << " ";
    }
}

缓冲的输出通常会随着流对象的销毁而刷新,因此上面的代码将打印(并非总是如此,ofc,但它适用于 gcc 4.6.3)

0 1 2 3..9
0 1 2 3..9

代替

0 0 1 1 2 2 3 3 .... 9 9 

我的输出

因为 unbufferedcerr会立即打印(第一个序列),而 bufferedcout会在main().

于 2012-07-09T09:44:42.567 回答