Я хочу иметь программу, в которой у пользователя есть 10 секунд для ввода пароля. Если таймер превышает 10 секунд, программа отображает сообщение. Мой текущий код таков:

 #include <iostream>
 #include <ctime>
 #include <string>

int main(){
std::string password;

int start_s=clock();

int stop_s=clock();
if(stop_s-start_s <= 0){

    std::cout << "TIME RAN OUT!";
}
std::cout << "Enter your password! \n";
std::cout << "Password: ";
std::cin >> password;
std::cout << "\n \n";

if (password == "password123"){

    std::cout << "Correct!";
} else {
    std::cout << "Wrong!";
}

}

Это, конечно, не работает ... Но я не уверен, что делать дальше ... Есть идеи?

Если вам нужны подробности, спрашивайте в комментариях.

< Сильный > EDIT :

Я просто понял, в чем проблема ... Потребовалась отметка времени, а затем быстро была сделана другая отметка времени. И когда разница была обнаружена, она была ниже 0 ...

Но я все еще не знаю, что делать дальше ...

6
BoeNoe 25 Ноя 2016 в 22:40

2 ответа

Лучший ответ

Что вы пытаетесь сделать, так это получить неблокирующее (асинхронное) чтение из stdin с таймаутом в 10 секунд. Это не так уж сложно, но в зависимости от вашего текущего уровня может потребоваться множество новых концепций.

Ключевой концепцией здесь является то, что cin >> password; является блокирующим вызовом, то есть, пока он не будет завершен, управление не будет передаваться дальше в этом коде. Поэтому нам нужно каким-то образом сделать его неблокирующим или оставить его блокирующим и выйти из него, когда истечет время ожидания.

Существует несколько распространенных реализаций, основанных на проектных требованиях и ограничениях системы. Каждая реализация отличается в зависимости от ОС, но методы очень похожи.

1. Асинхронный: STDIN с тайм-аутом Этот подход обычно используется в сетевом программировании и может быть распространен на другие формы ввода, такие как текущий случай.

  1. Поместите дескриптор стандартного ввода (STDIN) (handle = 0) в «список наблюдения».
  2. Поместите тайм-аут в список наблюдения.
  3. Всякий раз, когда есть изменение в STDIN, обрабатывайте его.
  4. Когда время ожидания истекло, проверьте, выполняет ли то, что мы обработали, работу.

В Linux (и многих других разновидностях Unix) список наблюдения может быть обработан с помощью FD_SET и системного вызова select. В Windows вам нужно будет использовать WaitForMultipleEvents.

Я не уверен, что смогу правильно объяснить эти концепции для целей этого вопроса. В качестве справки, еще один вопрос, в котором есть указатели на код для того же самого, здесь .

2. Синхронный: многопоточный с прерыванием Это распространенный метод, используемый в случаях, когда нам нужен подробный планировщик событий / таймер.

  1. Создайте два потока, A и B.
  2. A будет ждать по истечении указанного тайм-аута.
  3. B будет ждать блокирующего чтения
  4. Если A завершается (истекает время ожидания) до завершения B, A сигнализирует B и B решает, что делать дальше (завершить, повторить сообщение и т. Д.)
  5. Если B читает пароль и все в порядке, B сигнализирует A и просит его умереть.

Другой способ добиться того же - сделать поток прерывания ОС B, как описано в одном из комментарии.

3. Синхронный: опрос Это используется в тех случаях, когда нам не нужно слишком много детального контроля над временем.

  1. Проверьте, есть ли что-нибудь на входе, используя неблокирующее чтение (kbhit())
  2. Если его нет, и если в тайм-ауте осталось время, подождите меньшее количество времени delta (скажем 10ms)
  3. Если время ожидания истекло и времени больше не осталось, выполните необходимую обработку (отправьте сообщение пользователю, выйдите и т. Д.)

Обратите внимание, что в этом случае, в зависимости от delta, подход может потреблять много ресурсов ЦП и может быть неэффективным. Например, если delta=10ms, как указано выше, поток будет активироваться 100 раз каждую секунду, и это будет неэффективно, особенно когда пользователи не набирают символы на своей клавиатуре так быстро.

7
Community 23 Май 2017 в 12:08

Каноническое решение на C ++ должно выглядеть так:

#include <iostream>
#include <chrono>
#include <string>

int main() {
     std::string password;

     std::cout << "Enter your password! \n";
     std::cout << "Password: ";
     auto start_s = std::chrono::system_clock::now();
     std::cin >> password;

     auto stop_s = std::chrono::system_clock::now();
     if(stop_s - start_s >= std::chrono::seconds(10)) {
        std::cout << "TIME RAN OUT!";
     }
     else if (password == "password123") {
            std::cout << "Correct!";
     } else {
         std::cout << "Wrong!";
     }

}
-1
πάντα ῥεῖ 25 Ноя 2016 в 20:15