5

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;
}
Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • Are you sure it's a problem with your program, and not with the console itself? What are you actually doing when the output stops? And just in case it isn't the console but your program, *please* try to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) that you can show us. – Some programmer dude Feb 22 '18 at 12:22
  • 2
    I know this. (It trapped me also once.) It means a selection is pending in Console. Pressing [ESC] or [ENTER] aborts/finishs pending selection. While selection is pending the application stops and you see in the debugger it is waiting on some lock inside the... probably "Win32" code. – Scheff's Cat Feb 22 '18 at 12:22
  • I even didn't know that you can disable selection from your application. I just found a Q/A about this: [SO: How to disable user selection in Windows console](https://stackoverflow.com/a/46592932/7478597). – Scheff's Cat Feb 22 '18 at 12:29
  • Thank you, here's the minimal example: #include int main() { int i = 0; while (true) { i++; if (i%100000000 == 0) std::cout << i++ << "\n"; } return 0; } Run -> select -> press escape -> program continues to run (I seee it in Task Manager), but there's no output – user2419798 Feb 22 '18 at 12:30
  • I can do it even shorter: `#include int main() { for (;;) std::cout << '.' << std::flush; return 0; }`. ;-) (I'm not sure but I believe the `<< flush` isn't actually necessary.) – Scheff's Cat Feb 22 '18 at 12:35
  • OK, it seems the advice from the link above (DWORD prev_mode; auto hInput = GetConsoleWindow(); GetConsoleMode(hInput, &prev_mode); SetConsoleMode(hInput, prev_mode & ~ENABLE_QUICK_EDIT_MODE);) doesn't work, neither is std::flush – user2419798 Feb 22 '18 at 12:37
  • Sorry, you got me wrong. My sample was meant as [mcve] for the problem. (Otherwise, I had sent this as answer.) – Scheff's Cat Feb 22 '18 at 12:38
  • The code in the link ([SO: How to disable user selection in Windows console](https://stackoverflow.com/a/46592932/7478597)) I have not yet tested by myself. For me, pressing [ESC] is sufficient. We use the Console exclusively for debug output - no end user will ever see it. We even close it in release build explicitly. (All the diagnostic output may confuse end users and may force them to call us back - the most imaginable accident...) – Scheff's Cat Feb 22 '18 at 12:44
  • In my case ESC does remove selection and the program starts to run again (1 cpu core fully loaded), but there's no output for some reason. Could it be that the issue is in MSVC settings? I'd like to distribute this program and it's designed to be run for hours/days, and it's essential to have some output displayed - to report progress. If someone accidentally clicks on it and it either stops it or hides all output - that is highly undesirable... – user2419798 Feb 22 '18 at 12:49
  • So, there is no output anymore even although you [ESC]ed selection in Console? That effect is new to me. I'll check it out... – Scheff's Cat Feb 22 '18 at 12:59
  • You are absolutely right. Wow. (Our other applications are Console applications with Qt user interface. Could this make the difference?) – Scheff's Cat Feb 22 '18 at 13:11
  • So there's no this issue when using Qt? – user2419798 Feb 22 '18 at 13:21
  • I found a solution. (actually two solutions). I'm still typing. Qt has probably nothing to do with this but who knows. Please, wait a bit... – Scheff's Cat Feb 22 '18 at 13:30
  • Configure your console properly. Press Alt+Space > Properties > Options > untick the "QuickEdit Mode" checkbox. – Hans Passant Feb 22 '18 at 13:59

1 Answers1

5

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.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • just found a third solution - answer extended – Scheff's Cat Feb 22 '18 at 14:32
  • Thank you very much for your help! – user2419798 Feb 22 '18 at 16:19
  • the thread method does not work for me when QuickEdit mode (e.g. Mark) is active. the cout would still freeze. MSVC2015 / Win10 – rnd_nr_gen Aug 20 '18 at 12:14
  • @md_nr_gen This is true as long as something is marked in console. What happens if you finish copying in console or abort marking with [ESC]? Does output continue in this case? (In my case, it did. I've tested with VS2013 and `cmd` on Windows 10.) Btw. the sample only covers `std::cout`. If your output goes to `std::cerr`, the solution might need to consider this also. (Didn't test.) – Scheff's Cat Aug 20 '18 at 12:23
  • @md_nr_gen Concerning `std::cout` vs. `std::cerr`: I just modified the program so that it alternately prints on `std::cout` and `std::cerr`. After marking some text in console and pressing [ESC], the error output was skipped. Only, `std::cout` worked properly. – Scheff's Cat Aug 20 '18 at 12:39