Search code examples
c++consoleoutputinteraction

C++ program stops producing console output upon input to the console


I have a C++ program (MSVC 2017) which constantly outputs debug information via std::cout. However sometimes when I physically interact with the console (e.g. click on it accidentally) it stops producing output. Meaning that there's just nothing being printed, although the program continues to run and finishes doing whatever it's doing correctly.

Any ideas how to fix this? Removing std::cout buffer with "std::cout.setf(std::ios::unitbuf);" has no effect.

Sample:

#include <iostream>

int main()
{
  int i = 0;
  while (true) {
    i++;
    if (i%100000000 == 0) std::cout << i++ << "\n";
  }
  return 0;
}

Solution

  • This is what I did to reproduce the test – writing mcve.cc:

    #include <iostream>
    int main()
    {
      for (char i = 0;; ++i) std::cout << (int)i << std::flush;
      return 0;
    }
    

    I compiled and started in VS2013 (debug mode). It started to "blow" out numbers.

    I clicked into Console window and the output stopped (as described by the OP). After pressing ESC, I expected more numbers but nothing happened.

    I paused the debugging and looked through the call stack but there was nothing extra-ordinary. Stepping a bit, it even looked like the code is still executed. (The counting of i still happened as I could see in the Auto display of the debugger.)

    So, I started to apply the solution of another Q/A SO: How to disable user selection in Windows console. Though, it appeared to be of worth it was no MCVE. So, I had to complete it with use of google and 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;
    }
    

    This worked – QuickEdit disabled. (Clicking into Console window didn't stop output anymore.)

    However, without this trick it should work as well. (It was bothering me that I didn't understand this.) After thinking a while, I came to the enlighting idea. Could it be that the std::cout was bad() after QuickEdit?

    So, I made a third version. As I couldn't use the coutput I modified i which I could watch in the debugger. (Actually, the return of std::cout::good() was displayed as well but with assignment to i it is even more illustrative.)

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

    After QuickEdit selection and ESC, the i was constantly 0. Hence, the other fix is obvious: The std::cout should be clear()ed periodically:

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

    I'm not sure which of the both solutions I like more:

    • The former is least invasive (just an addition to the beginning of main()).
    • the latter is pure C++ (without platform specific code) which I prefer in general.

    It would be interesting to get a remark about this concerning non-Windows platforms...

    I cannot remember that I've ever seen such QuickEdit issue on Linux (nor Irix or Solaris – the OSes I've used once in the past). On that systems, selections were handled (in my case) by the Xterm/X11 – beyond the scope of stream I/O.

    So, is it even possible that std::cout becomes bad on that systems (assuming there were no encoding errors in the output)?


    Finally, I found a portable non-invasive method (at the cost of multi-threading):

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

    It starts an extra thread to do the periodical check/clean of std::cout. This is something else which has to be added to main() only (what I consider as "non-invasive fix") – the actual code base doesn't need to be changed.

    A note: I was a little bit in doubt whether concurrent access to std::cout is safe (although I believed to remember it is). Regarding this, I found another Q/A SO: Is cout synchronized/thread-safe?. According to the accepted answer in this link, it is guaranteed (or at least required) starting with C++11.