Input with a timeout in C++
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.
- Place the standard input (STDIN) handle (handle = 0) into a 'watch-list'.
- Place a timeout on the watch-list.
- Whenever there is a change in the STDIN, process it.
- 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.
- Create two threads,
A
andB
. A
will wait on the indicated timeout.B
will wait on a blocking read- If
A
terminates (times out) beforeB
finishes,A
signalsB
andB
decides what to do next (terminate, repeat a message etc) - If
B
reads the password and it's fine,B
signalsA
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.
- Check if there is anything in the input using a non-blocking read (
kbhit()
) - If there is none, and if there is time remaining in the timeout, wait for a smaller amount of time
delta
(say10ms
) - 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.