Input with a timeout in C++

寵の児 提交于 2020-01-10 03:05:30

问题


I want to have a program where the user have 10 seconds to enter the password. If the timer goes over 10 seconds, the program displays a message. My current code is this:

 #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!";
}

}

This of course is not working... But I am not sure what to do next... Any ideas?

If you need more details, ask in the comments.

EDIT:

I just realized what the problem was... It took a time stamp and then quickly made another time stamp. And when the difference was found, it was below 0...

But I still don't know what to do next...


回答1:


What you are trying to do is to have an non-blocking (asynchronous) read from stdin with a timeout of 10 seconds. This is not too tough but may involve many new concepts depending on your current level.

The key concept here is that cin >> password; is a blocking call, i.e., until it is completed, control will not flow further in this code. So we need to make it non-blocking in some way, or keep it blocking and break out of it when the timeout expires.

There are a few common implementations based on the design requirements and constraints of the system. Each implementation is different depending on the OS but the techniques are very similar.

1. Asynchronous: STDIN with timeout This approach is commonly used in network programming and can be extended to other forms of input such as the current case.

  1. Place the standard input (STDIN) handle (handle = 0) into a 'watch-list'.
  2. Place a timeout on the watch-list.
  3. Whenever there is a change in the STDIN, process it.
  4. When the timeout has expired, check if what we have processed does the job.

In Linux (and many other Unix flavors), the watch-list can be handled using FD_SET and a select system call. In Windows, you will need to use WaitForMultipleEvents.

I'm not sure I can do justice to explaining these concepts accurately for the purposes of this question. As a reference, another question which has some code pointers for exactly the same thing is here.

2. Synchronous: Multithreaded with Interrupt This is a common technique used for cases where we need a fine-grained event-scheduler / timer.

  1. Create two threads, A and B.
  2. A will wait on the indicated timeout.
  3. B will wait on a blocking read
  4. If A terminates (times out) before B finishes, A signals B and B decides what to do next (terminate, repeat a message etc)
  5. If B reads the password and it's fine, B signals A and asks it to die.

Another way to achieve the same is to make the OS interrupt thread B as described in one of the comments.

3. Synchronous: Polling This is used for cases where we don't need too much of a fine-grained control over time.

  1. Check if there is anything in the input using a non-blocking read (kbhit())
  2. If there is none, and if there is time remaining in the timeout, wait for a smaller amount of time delta (say 10ms)
  3. If the timeout has expired and there is no more time remaining, do whatever processing is needed (message the user, exit etc)

Note that in this case, depending on the delta, the approach may consume a lot of CPU and may be inefficient. For example, if delta=10ms as above, the thread will be woken up 100 times every second and it will be not efficient, especially when users do not type characters on their keyboard that fast.




回答2:


A canonical c++ solution should look like:

#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!";
     }

}


来源:https://stackoverflow.com/questions/40811438/input-with-a-timeout-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!