输入到控制台后,C ++程序将停止产生控制台输出 [英] C++ program stops producing console output upon input to the console

查看:188
本文介绍了输入到控制台后,C ++程序将停止产生控制台输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C ++程序(MSVC 2017),该程序不断通过std :: cout输出调试信息.但是有时当我与控制台进行物理交互时(例如,无意中单击它),它将停止产生输出.这意味着尽管程序会继续运行并完成正确的工作,但什么也没打印.

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.

有什么办法解决此问题吗?使用"std :: cout.setf(std :: ios :: unitbuf);"删除std :: cout缓冲区没有效果.

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

示例:

#include <iostream>

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

推荐答案

这是我为重现测试而做的–写mcve.cc:

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

我在VS2013(调试模式)下编译并启动.它开始吹"出数字.

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

我单击进入控制台窗口,然后停止输出(如OP所述).按 ESC 后,我希望有更多数字,但什么也没发生.

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的计数仍然发生.)

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.)

因此,我开始应用另一个Q/A的解决方案 SO:如何在Windows控制台中禁用用户选择 .但是,似乎值得的不是 MCVE .因此,我必须使用google和MSDN来完成它:

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.)

但是,没有这个技巧,它也应该可以正常工作. (我不明白这一点让我感到困扰.)经过一会儿思考,我想到了一个很有启发性的想法.快速编辑后std::coutbad()吗?

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?

因此,我制作了第三个版本.由于无法使用cout put,因此我修改了i,可以在调试器中查看它. (实际上,也显示了std::cout::good()的返回值,但将其分配给i则更具说明性.)

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

在选择QuickEdit和 ESC 之后,i一直是0.因此,另一个解决方法是显而易见的:std::cout应该定期clear() ed:

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:

  • 前者的侵入性最小(只是main()开头的补充).
  • 后者是我一般更喜欢的纯C ++(没有特定于平台的代码).
  • 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.

在非Windows平台上对此进行评论将很有趣...

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

我不记得我曾经在Linux上看到过这样的QuickEdit问题(我过去也没有使用过Irix或Solaris的OS).在该系统上,选择是由Xterm/X11处理的.超出了流I/O的范围.

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.

那么,std::cout是否有可能在该系统上变坏(假设输出中没有编码错误)?

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

它启动一个额外的线程来定期检查/清理std::cout.这是仅需添加到main()中的其他内容(我认为这是非侵入式修复程序")–实际的代码库不需要更改.

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.

注意:我有点怀疑并发访问std::cout是否安全(尽管我相信还记得).关于这一点,我找到了另一个问与答 SO:cout是同步的/线程安全的吗?.根据此链接中可接受的答案,可以保证(或至少是必需的)从C ++ 11开始.

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.

这篇关于输入到控制台后,C ++程序将停止产生控制台输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆