簡體   English   中英

C ++ cout和cin緩沖區,以及一般的緩沖區

[英]C++ cout and cin buffers, and buffers in general

有人可以更明確地解釋緩沖區的概念嗎? 我知道緩沖區是存儲字符的數據結構,以及從中讀取數據的位置。 沖洗緩沖區的想法是什么?

刷新緩沖區時,這是指寫入存儲在其中的字符的行為嗎?

從文字:

To avoid the overhead of writing in response to each output request, the library uses the 
buffer to accumulate the characters to be written, and flushes the buffer, by writing its
contents to the output device, only when necessary. By doing so, it can combine several 
output operations into a single write.

當提到“刷新”時,幾乎使其聽起來好像緩沖區正在寫入但同時也被擦除。 只是猜測。

那么,為了寫入屏幕上的視圖需要緩沖區刷新?

When our program writes its prompt to cout, that output goes into the buffer associated
with the standard output stream. Next, we attempt to read from cin. This read flushes
the cout buffer, so we are assured that our user will see the prompt.

在這里,聽起來好像通過在結尾處使用'endl'它告訴系統它需要立即寫入(暗示否則不會?)什么是endl未使用?

Writing the value of std::endl ends the line of 
output, and then flushes the buffer, which forces the system to write to the output 
stream immediately.

緩沖的基本思想是將操作組合成更大的塊:而不是讀取少量字節,讀取整個頁面並按要求使其可用; 而不是寫入少量字節,緩沖它們並寫入整個頁面或明確請求寫入時。 從本質上講,這是一項重要的性能優化。 對於I / O操作來說非常明確,但通常也適用於其他用途:一次處理多個單元通常最終比處理單個單元更快。

關於I / O 刷新是指將當前緩沖的字節寫入其目的地 - 無論這在實踐中意味着什么。 對於C ++,IOStreams刷新流量相當於調用成員函數std::ostream::flush() ,后者又調用相關流緩沖區上的std::streambuf::pubsync() (這忽略了流實際上是類的細節)模板,例如std::basic_ostream<cT, traits> ;為了討論的目的,它們是類模板並不重要:基類std::streambuf是C ++關於如何處理某個流的抽象。 它在概念上分別由輸入和輸出緩沖器以及負責讀取或寫入緩沖器的虛函數組成。 函數std::streambuf::pubsync()調用虛函數std::streambuf::sync() ,應該為每個可能緩沖字符的流緩沖區重寫該函數。 也就是說, 刷新實際意味着什么取決於虛擬功能的實現方式。

是否覆蓋sync()實際上做了什么以及它做了什么顯然取決於流緩沖區代表什么。 例如,對於負責讀取或寫入文件的std::filebufsync()寫入緩沖區的當前內容並從緩沖區中刪除已刷新的字符。 鑒於文件可能並不真正代表物理文件,而是例如與不同進程通信的命名管道,這是合理的行為。 另一方面,刷新一個std::stringbuf ,它是用於實現寫入std::string的流緩沖區,例如由std::ostringstream實際上沒有做任何事情:字符串完全在程序和std::string當調用std::stringbuf::str()成員函數時,將構造表示其值的std::string 對於用戶定義的流緩沖區,有許多不同的行為。 一個常見的流緩沖區類是在將輸出傳遞給另一個流緩沖區之前以某種方式過濾輸出(例如,日志緩沖區可能在每個換行符后添加時間戳)。 這些通常只調用下一個流緩沖區的std::streambuf::pubsync()函數。

因此,對實際行為的描述通常保持相當模糊,因為不清楚究竟發生了什么。 從概念上講,刷新流或在流緩沖區上調用pubsync()應該更新字符的外部目標以匹配當前的內部狀態。 通常,這相當於轉發當前緩沖的字符並將其從內部緩沖區中刪除。 在這一點上值得注意的是,緩沖區通常也會在它剛剛滿時寫入。 當它變滿時再次依賴於特定的流緩沖區。 std::filebuf一個很好的實現基本上會填充一個匹配底層頁面大小(或其倍數)的字節緩沖區,然后編寫完整的頁面,最大限度地減少所需的I / O操作數量(這實際上相對比較棘手)因為不同文件系統之間的緩沖區大小不同,並且根據編寫生成的字節數時使用的編碼不能輕易估計)。

標准C ++庫通常不需要顯式刷新:

  • std::cerr設置為自動刷新在調用每個輸出操作后產生的任何輸出。 這是格式化標志std::ios_base::unitbuf默認設置的結果。 要關閉此功能,您可以使用std::cerr << std::nounitbuf或者只能使用std::clog寫入同一目的地,但不能執行此刷新。
  • std::istream讀取時,刷新“綁定” std::ostream (如果有)。 默認情況下, std::coutstd::cin綁定。 如果你想自己設置一個綁定的std::ostream你可以使用例如in.tie(&out)或者如果你想刪除一個綁定的std::ostream你可以使用例如std::cin.tie(0)
  • std::ostream被銷毀時(或者當std::ostream是標准流之一時它通常會被銷毀), std::ostream被刷新。
  • 當流的緩沖區溢出時,調用虛函數std::streambuf::overflow() ,它通常將當前緩沖區的緩沖區(加上傳遞的字符,如果有的話)寫入其目的地。 這通常是通過調用sync()來清除當前緩沖區來完成的,但再次完成的操作取決於具體的流緩沖區。

您還可以顯式請求刷新std::ostream

  • 您可以調用成員函數std::ostream::flush() ,例如std::cout.flush()
  • 你可以調用成員函數std::streambuf::pubsync() ,例如std::cout.rdbuf()->pubsync() (假設有一個流緩沖區設置;調用std::ostream::flush()如果沒有流緩沖區,則不會執行任何操作。
  • 你可以使用操縱std::flush ,例如std::cout << std::flush
  • 您可以使用操縱符std::endl ,例如std::cout << std::endl來首先編寫換行符然后刷新流。 請注意, 只有在真正意味着刷新輸出時才應使用std::endl 當你真的只想創建一個行尾時, 不要使用std::endl 只為后者寫一個換行符!

在任何情況下,如果您只編寫幾個不會導致流緩沖區緩沖區溢出的字符,那么在它們被隱式或顯式刷新之前不會發生任何事情。 通常,這不是問題,因為緩沖輸出需要變得可用的正常情況,即從std::cin讀取時,由std::cout處理tie() d到std::cin 當使用其他I / O機制時,可能需要明確地tie()相關的流。 如果程序在調試期間“崩潰”或斷言,緩沖區有時會出現問題,因為某些流輸出可能已經發出但尚未發送。 解決這個問題的方法是使用std::unitbuf

想想如果每次“寫入”一個字節到磁盤文件,你的程序實際上去了磁盤,在當前扇區/集群/塊中讀取,更改單個字節然后將其寫回物理,會發生什么情況磁盤。

我會說你的軟件在性能方面最好被描述為“冰川”:-)

緩沖是一種對讀取和寫入進行批處理的方法,以提高它們的效率。

例如,如果您正在寫入磁盤文件,它可能會等到您有一個完整的4K塊然后再將其寫入磁盤。

在讀取時,即使您只詢問了10個字節,也可能會獲得4K塊,前提是您可能會在短時間內要求其余部分。

寫入時刷新會在緩存已滿時隱式發生,或者在請求時顯式發生(使用刷新調用或關閉文件時)。

請注意,此文件緩沖只是一種緩沖,該概念可用於任何可以通過“分塊”讀取和寫入來提高效率的地方。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM