Условие цикла с использованием getch() не завершает цикл, как ожидалось

У меня есть следующий код, но он не завершает цикл while, даже если done истинно. Он продолжает ждать _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 истинно?


person user1833852    schedule 08.02.2019    source источник
comment
Предоставьте минимальный воспроизводимый пример   -  person Kunal Puri    schedule 09.02.2019
comment
Где сделано изменено? Это многопоточный код?   -  person Christophe    schedule 09.02.2019
comment
done имеет логическое значение и устанавливается в TRUE потоком после завершения потока.   -  person user1833852    schedule 09.02.2019
comment
Я надеюсь, что done является атомарным.   -  person rustyx    schedule 09.02.2019


Ответы (1)


Условия цикла записываются так:

  • если done истинно, логическое выражение замыкается и тело цикла вводится без оценки правой части условия.
  • если done ложно, то вызывается _getch(). Если возвращается char, выражение будет истинным, и будет введено тело цикла. Если нет доступного символа, _getch() будет ждать, пока пользователь не введет его. Цикл будет прерван только в том случае, если будет обнаружен конец файла (например, Ctrl+Z вводится в терминальном режиме или cin перенаправляется из файла и достигается его конец).

Если вам нужен неблокирующий ввод с клавиатуры, вам придется использовать _kbhit() сначала проверить, доступен ли символ, а затем прочитать только символ с _getch(). Для kbhit() в Linux вы можете посмотреть здесь.

Редактировать: ваше многопоточное редактирование

Прежде всего, если done — это переменная, которая используется в обоих потоках (что, по-видимому, так и есть, поскольку она не изменяется в цикле), убедитесь, что она объявлена ​​как atomic. Если это не так, у вас будет состояние гонки, которое является UB.

Ваше повествование не соответствует коду. Если done — это когда другой поток завершился, и вы хотите завершить цикл в этот момент, вам нужно зациклиться на !done.

Кроме того, если вы хотите зацикливаться, пока работает другой поток, но проверить клавиатуру и позволить пользователю прервать код, вам лучше сделать эту проверку в цикле. Кстати, это может быть вариант пройти sleep_for пару миллисекунд в теле цикла, чтобы не тратить слишком много ресурсов ЦП на запросы к клавиатуре.

Таким образом, код будет иметь такую ​​​​структуру, как

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() вам все равно придется ждать завершения другого потока.

person Christophe    schedule 09.02.2019
comment
Привет Кристоф, Спасибо. Любая идея о том же API для Linux env? - person user1833852; 09.02.2019
comment
Я считаю, что мне нужно присоединиться к потоку после цикла while. Ниже приведен код. Но Loop не выполняется, когда я нажимаю клавишу. поток т (начало, папка_путь); while (done || ((c = _getch()) != EOF)) { cout ‹‹ Операция прервана ‹‹ endl; выход_сигнал.set_value(); ломать; } t1.join(); cout ‹‹ Операция завершена ‹‹ endl; - person user1833852; 09.02.2019
comment
@ user1833852 для kbhit в Linux вы можете посмотреть здесь: stackoverflow.com/a/29335796/3723423 - person Christophe; 09.02.2019
comment
@user1833852 user1833852 хорошо, я видел ваше редактирование и соответственно обновил свой ответ - person Christophe; 09.02.2019
comment
Спасибо Кристоф за вашу помощь. - person user1833852; 11.02.2019