Is it possible to set timeout for std::cin?
It isn't possible to set a time out for std::cin
in a portable way. Even when resorting to non-portable techniques, it isn't entirely trivial to do so: you will need to replace std::cin
's stream buffer.
On a UNIX system I would replace the default stream buffer used by std::cin
by a custom one which uses file descriptor 0
to read the input. To actually read the input I would use poll()
to detect presence of input and set a timeout on this function. Depending on the result of poll()
I would either read the available input or fail. To possibly cope with typed characters which aren't forwarded to the file descriptor, yet, it may be reasonable to also turn off the buffering done until a newline is entered.
When using multiple threads you can create a portable filtering stream buffer which uses on thread to read the actual data and another thread to use a timed condition variable waiting either for the first thread to signal that it received data or for the time out to expire. Note that you need to guard against spurious wake-ups to make sure that the timeout is indeed reached when there is no input. This would avoid having to tinker with the actual way data is read from std::cin
although it still replaces the stream buffer used by std::cin
to make the functionality accessible via this name.
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.
How to implement timeout for function in c++
You can create a separate thread to run the call itself, and wait on a condition variable back in your main thread which will be signalled by the thread doing the call to f
once it returns. The trick is to wait on the condition variable with your 1s timeout, so that if the call takes longer than the timeout you will still wake up, know about it, and be able to throw the exception - all in the main thread. Here is the code (live demo here):
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std::chrono_literals;
int f()
{
std::this_thread::sleep_for(10s); //change value here to less than 1 second to see Success
return 1;
}
int f_wrapper()
{
std::mutex m;
std::condition_variable cv;
int retValue;
std::thread t([&cv, &retValue]()
{
retValue = f();
cv.notify_one();
});
t.detach();
{
std::unique_lock<std::mutex> l(m);
if(cv.wait_for(l, 1s) == std::cv_status::timeout)
throw std::runtime_error("Timeout");
}
return retValue;
}
int main()
{
bool timedout = false;
try {
f_wrapper();
}
catch(std::runtime_error& e) {
std::cout << e.what() << std::endl;
timedout = true;
}
if(!timedout)
std::cout << "Success" << std::endl;
return 0;
}
Related Topics
Constant Expression Initializer for Static Class Member of Type Double
Why Is the Empty Base Class Optimization (Ebo) Is Not Working in Msvc
How to Deploy a Qt Application on Windows
How Do Compilers Treat Variable Length Arrays
Behavior When Dereferencing the .End() of a Vector of Strings
Is Reading an Indeterminate Value Undefined Behavior
Scope VS Life of Variable in C
How to Read Files in Sequence from a Directory in Opencv
Random Output Different Between Implementations
Statically Declared 2-D Array C++ as Data Member of a Class
C++ Template Copy Constructor on Template Class
Rvalue to Lvalue Conversion Visual Studio
Inlining Failed in Call to Always_Inline '_M256D _Mm256_Broadcast_Sd(Const Double*)'
How to Store Functional Objects with Different Signatures in a Container
Why Sizeof(Int) Is Not Greater Than -1
Waitforinputidle Doesn't Work for Starting Mspaint Programmatically