2012-07-09 136 views
2

據我所知,在默認情況下通過C++支持的所有流IO被緩衝。C++緩衝流IO

這意味着要輸出的數據被放入緩衝區,直到它滿,然後發送到輸出設備,同樣輸入,數據讀取一次緩衝區是空的......這一切是這樣做的昂貴的系統調用次數可以最小化。

但如何驗證行動這一行爲。我的意思是考慮下面的代碼

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

這裏緩衝進入圖片在哪裏?我知道有緩衝發生,但如何解釋它?輸出在屏幕上立即可見,那麼實際上可以看到緩衝I/O的實際代碼示例呢?

+0

在cout的情況下,緩衝區是1個字節。當您讀/寫文件時,真正的緩衝進入播放。 – 2012-07-09 09:42:12

+0

@Anubis先生你是怎麼做到的?不,這不一定是真的。 – 2012-07-09 09:43:01

+0

@KonradRudolph嗯,我不記得那個說法的來源,但它是在大多數情況下會發生什麼 – 2012-07-09 09:45:00

回答

4

試試下面的程序。 sleep(1)用於引入的延遲(1秒),我使用Linux,所以sleep對我的作品。如果您無法使其工作,請嘗試其他方式來延遲此程序(例如,簡單的for循環)。如果您沒有看到任何緩衝效果,您也可以嘗試增加緩衝區大小(取消評論的註釋行代碼)。

在我的操作系統(Linux 3.2.0)和編譯器(g++ 4.6.3)上,該程序打印「Portion1Portion2」,然後打印「Portion3Portion4」,然後打印「Portion5」。 std :: endl guaranteed to flush緩衝區,但正如你所看到的,換行符也適用於我這種方式。

#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; 
} 
+0

不適用於VS2010 :-(。沒有緩衝發生! – Arun 2012-07-09 10:30:28

+1

即使行未註釋? – 2012-07-09 16:48:14

+1

線條未評論它的作品! Yepeee ...謝謝Nya :-) – Arun 2012-07-10 05:23:31

4

嘗試以下代碼:

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

緩衝輸出通常與流對象的破壞沖洗,所以上面的代碼將打印(不總是,OFC,但它確實對我用gcc 4.6 0.3)

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

代替

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

my output

由於未緩衝的cerr是立即打印(第一個序列),並且緩衝區cout打印在main()的末尾。

+0

我在VS2010中試過這個,給出了序列0 0 1 1 2 2 ... – Arun 2012-07-09 10:11:28

+0

@Arun,這就是爲什麼我說「不總是」。緩衝是特定於實現的,因此您將看到不同編譯器和設置的不同結果。有時輸出甚至可能以奇怪的順序混合。 – SingerOfTheFall 2012-07-09 10:22:49

+0

'std :: cout'永遠不會被破壞,但是緩衝區可以被其他原因刷新。在這種情況下,'std :: cin'和'std :: cerr'都綁定到'std :: cout',這意味着其中一個IO上的任何IO都會使用'std :: cout'。 'std :: cerr'被單元緩衝,這意味着每個'<<'運算符在操作結束時刷新它。 – 2012-07-09 10:24:08

7

首先,並非所有iostream都被緩衝;緩衝由所附 streambuf處理。在使用filebuf(由ifstreamofstream使用)的情況下,輸入將盡可能多地讀取,直到達到緩衝區的大小,並且輸出將在溢出時刷新緩衝區,當發生明確刷新或關閉時,或者當對象被破壞時(其中 隱式調用關閉)。

cout的情況有點特別,因爲它永遠不會被破壞,也不會被關閉。系統有一個保證,flush將在exit被調用後調用至少一次 (當您從main返回時會發生什麼 )。這意味着從主返回的 之前的任何輸出都將被刷新;如果您使用cout, 靜態對象的析構函數,則仍然需要顯式刷新爲 。

也可能將tie輸出流轉換爲輸入流; cout 默認綁定到cin。在這種情況下,任何試圖從 輸入捆綁流將刷新輸出。

通常的約定是隻使用std::endl而不是簡單的 輸出'\n'; std::endl輸出'\n',然後刷新 流。對於所有輸出非常重要的數據流,要立即出現 ,有一個可以設置的unitbuf標誌,這意味着該數據流將在每個運算符的末尾被刷新。 (std::cerr有這個缺省設置)。

最後,如果你想看到緩衝的作用,把像 sleep(10)你的輸出之後。如果立即顯示輸出,則已經刷新了 ;如果它沒有被緩衝,並且在sleep之後隱式發生沖刷 。

+0

感謝您的回覆。但是,如果您能夠提供一個能夠始終如一地工作的代碼示例,那將會很棒。 – Arun 2012-07-09 11:05:19

+0

@Arun它一直在做什麼?使用'std :: endl'而不是''\ n''會在每行的結尾處引起刷新。如果你需要更多,'std :: cout << std :: flush'將無條件地刷新輸出。 – 2012-07-09 11:26:09

+0

我需要一個描述緩衝區角色的例子。 類似於 cout <<「Hello world」; //這裏輸出在控制檯上看不到 cout << endl; //現在你可以在控制檯上看到世界。 – Arun 2012-07-09 12:59:04