[英]C++ program stops producing console output upon input to the console
我有一個C ++程序(MSVC 2017),它通過std :: cout不斷輸出調試信息。 然而,有時當我與控制台進行物理交互時(例如意外點擊它),它會停止產生輸出。 這意味着沒有任何東西被打印出來,雖然程序繼續運行並完成了正確執行的操作。
任何想法如何解決這一問題? 使用“std :: cout.setf(std :: ios :: unitbuf);”刪除std :: cout緩沖區 沒有效果。
樣品:
#include <iostream>
int main()
{
int i = 0;
while (true) {
i++;
if (i%100000000 == 0) std::cout << i++ << "\n";
}
return 0;
}
這就是我重現測試所做的 - 編寫mcve.cc
:
#include <iostream>
int main()
{
for (char i = 0;; ++i) std::cout << (int)i << std::flush;
return 0;
}
我編譯並在VS2013(調試模式)中啟動。 它開始“吹噓”數字。
我點擊進入控制台窗口,輸出停止(如OP所述)。 按ESC后 ,我預計會有更多數字,但什么都沒發生。
我暫停了調試並查看了調用堆棧,但沒有什么特別的。 踩了一下,看起來代碼仍然執行。 (正如我在調試器的自動顯示中看到的那樣, i
的計數仍然發生。)
所以,我開始應用另一個Q / A SO的解決方案:如何在Windows控制台中禁用用戶選擇 。 雖然,它看起來是值得的,但沒有MCVE 。 所以,我必須使用谷歌和MSDN完成它:
#include <iostream>
#include <Windows.h>
int main()
{
// disable QuickEdit mode in Console
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD prev_mode;
GetConsoleMode(hInput, &prev_mode);
SetConsoleMode(hInput, prev_mode & ~ENABLE_QUICK_EDIT_MODE);
// start test
for (char i = 0;; ++i) std::cout << (int)i << std::flush;
// done (never reached)
return 0;
}
這工作 - 禁用QuickEdit。 (單擊控制台窗口不再停止輸出。)
但是,沒有這個技巧它也應該工作。 (這讓我感到困擾,我不理解這一點。)經過一段時間的思考,我找到了令人愉快的想法。 可能是在QuickEdit之后std::cout
是bad()
嗎?
所以,我做了第三個版本。 由於我無法使用cout
put我修改了i
,我可以在調試器中觀看。 (實際上,還顯示了std::cout::good()
的返回,但是對i
賦值則更具說明性。)
#include <iostream>
#include <Windows.h>
int main()
{
for (char i = 0;; ++i) {
if (!std::cout.good()) i = 0;
std::cout << (int)i << std::flush;
}
return 0;
}
在QuickEdit選擇和ESC之后 , i
始終為0
。 因此,另一個修復是顯而易見的: std::cout
應該定期clear()
:
#include <iostream>
#include <Windows.h>
int main()
{
for (char i = 0;; ++i) {
if (!std::cout.good()) std::cout.clear();
std::cout << (int)i << std::flush;
}
return 0;
}
我不確定我更喜歡哪兩種解決方案:
main()
開頭的一個補充)。 有關非Windows平台的評論會很有意思......
我不記得我曾經在Linux上看到過這樣的QuickEdit問題(也不是Irix或Solaris - 我過去曾經使用過的操作系統)。 在那個系統上,Xterm / X11處理了選擇(在我的例子中) - 超出了流I / O的范圍。
那么,是否有可能std::cout
在該系統上變壞(假設輸出中沒有編碼錯誤)?
最后,我發現了一種便攜式非侵入式方法(以多線程為代價):
#include <atomic>
#include <iostream>
#include <thread>
int main()
{
// spawn extra thread to clean cout periodically
std::atomic<bool> exitThreadClearCOut = false;
std::thread threadClearCOut([&]() {
while (!exitThreadClearCOut) {
if (!std::cout.good()) std::cout.clear();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// 100 ms - nearly non-perceptable for humans but an "eternity" for modern CPUs
}
});
// start main work
for (char i = 0;; ++i) {
std::cout << (int)i << std::flush;
}
// finish/join thread to clean cout periodically
exitThreadClearCOut = true;
threadClearCOut.join();
// done
return 0;
}
它啟動一個額外的線程來定期檢查/清除std::cout
。 這是必須添加到main()
其他東西(我認為是“非侵入式修復”) - 實際的代碼庫不需要更改。
注意:我有點懷疑對std::cout
並發訪問是否安全(盡管我相信它會記住它)。 對此,我發現了另一個Q / A SO:cout同步/線程安全嗎? 。 根據此鏈接中接受的答案,從C ++ 11開始保證(或至少需要)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.