簡體   English   中英

C ++程序在輸入到控制台時停止生成控制台輸出

[英]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::coutbad()嗎?

所以,我做了第三個版本。 由於我無法使用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()開頭的一個補充)。
  • 后者是純C ++(沒有特定於平台的代碼),我更喜歡它。

有關非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.

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