使用 getch() 的循环条件不会按预期结束循环

Loop condition using getch() does not end the loop as expected

我有以下代码,但即使 done 为真,它也不会结束 while 循环。它一直在等待 _getch():

   while (done || ((c = _getch()) != EOF))
   {
       cout << "Operation aborted" << endl;
       break;
   }
   cout << "Operation finished" << endl;

编辑: 事实上,我希望能够中断在另一个线程中执行的长时间操作。我相信我必须在 while 循环之后加入线程。但是使用下面的代码,当我按下一个键时,循环不会被执行。

thread t(Start, folder_path);
while (done || ((c = _getch()) != EOF))
{
    cout << "Operation aborted" << endl;
    exit_signal.set_value();
    break;
}
t1.join();
cout << "Operation finished" << endl;

done 为真时如何结束循环?

循环条件的写法是:

  • 如果done为真,逻辑表达式被短路并进入循环体而不评估条件的右侧。
  • 如果 done 为假,则调用 _getch()。如果返回的是char,则表达式为真,进入循环体。如果没有可用的字符,_getch() 将等待用户键入一个字符。只有遇到文件末尾(即在终端模式下输入 Ctrl+Z,或从文件重定向 cin 并到达其末尾),循环才会被中断。

如果你想要一个非阻塞的键盘输入,你必须使用 _kbhit() first, to check if a char is available, and then only read the char with _getch(). For kbhit() on linux, you may have a look

编辑:您的多线程编辑

首先,如果 done 是一个在两个线程中都使用的变量(显然是这样,因为它在循环中没有改变),确保它声明为 atomic。如果不是这种情况,那么您的竞争条件就是 UB。

现在,您的叙述与代码不符。如果 done 是另一个线程完成的时候,而你想在这一刻结束循环,你需要在 !done 上循环。

此外,如果你想在另一个线程运行时循环,但检查键盘并让用户中断代码,你最好在循环中进行检查。顺便说一下,可以选择在循环体中运行 sleep_for 几毫秒,以避免浪费太多 CPU 来查询键盘。

所以代码最终会以

这样的结构结束
std::atomic<bool> done(false); 
...
thread t(Start, folder_path);
while (!done)
{   
    if (_kbhit() && ((c = _getch()) != EOF) { // if keystroke available
        cout << "Operation aborted" << endl;
        exit_signal.set_value();  // assuming this would make t1 return from folder_path()
        break;
    }
    std::this_thread::sleep_for (std::chrono::milliseconds(500));
    // update status bar or do other stuff 
}
t1.join();
cout << "Operation finished" << endl;

终于不知道exit_signal.set_value();在干什么了。我希望它确实做了一些事情来告诉另一个线程停止处理。如果没有,您的循环将结束,但在 join() 处您无论如何都必须等待另一个线程完成。