Is there a way to implement timeout in the std::async method, so I want this call to timeout and complete if the thread hasnt completed for the specified amount of time. How can I implement this functionality.
There is no (standard) way to reach into a thread and kill it, and this is generally a bad idea anyway. The much cleaner option is to pass a starting time and max duration to the function and then (possibly multiple times as the calculation progresses) check if the current time minus the starting time is too long.
I would make something like this:
#include <chrono>
template <typename Clock = std::chrono::steady_clock>
class timeout
{
public:
typedef Clock clock_type;
typedef typename clock_type::time_point time_point;
typedef typename clock_type::duration duration;
explicit timeout(duration maxDuration) :
mStartTime(clock_type::now()),
mMaxDuration(maxDuration)
{}
time_point start_time() const
{
return mStartTime;
}
duration max_duration() const
{
return mMaxDuration;
}
bool is_expired() const
{
const auto endTime = clock_type::now();
return (endTime - start_time()) > max_duration();
}
static timeout infinity()
{
return timeout(duration::max());
}
private:
time_point mStartTime;
duration mMaxDuration;
};
This simple utility tracks the starting time and a max duration (and provides a way of specifying infinity), and allows the user to query simple facts, most importantly whether or not a timeout has occurred.
Test below; you can add fake delay by defining/undefining FAKE_DELAY
:
#include <iostream>
#include <future>
#define FAKE_DELAY
void fake_delay()
{
#ifdef FAKE_DELAY
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
#endif
}
void short_running_function(timeout<> timelimit)
{
fake_delay();
if (timelimit.is_expired())
std::cout << "short running thread ran out of time" << std::endl;
else
std::cout << "short running function finished" << std::endl;
}
void long_running_function(timeout<> timelimit)
{
for (unsigned i = 0; i < 10; ++i) {
if (timelimit.is_expired())
{
std::cout << "long running thread ran out of time" << std::endl;
return;
}
std::cout << "long running thread doing work" << std::endl;
fake_delay();
}
std::cout << "long running function finished" << std::endl;
}
int main()
{
std::async(short_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();
std::async(short_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();
std::async(long_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();
std::async(long_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();
std::async(long_running_function,
timeout<>::infinity()).wait();
}
One possible output with FAKE_DELAY
off:
short running function finished
short running function finished
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running function finished
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running function finished
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running function finished
One possible output with FAKE_DELAY
on:
short running thread ran out of time
short running function finished
long running thread doing work
long running thread ran out of time
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread ran out of time
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running thread doing work
long running function finished
The standard does not provide any way to non-cooperatively kill a thread. The lack of automatic timeout functionality is just another example of this.
Instead you must implement the code you pass to std::async
to handle doing this cooperatively. One pattern for cooperatively killing a thread is to pass to the function an object which provides a method to check if the async function should continue, and if not it throws an exception.
struct Time_out {
std::chrono::steady_clock start = std::chrono::steady_clock::now();
std::chrono::milliseconds timeout;
Time_out(std::chrono::milliseconds t) : timeout(t) {}
void check() {
if (start + timeout < std::chrono::steady_clock::now())
throw timeout_exception();
}
};
std::future<void> f = std::async([](Time_out t) {
while(more work) {
// do work
t.check();
}
}, Time_out(std::chrono::seconds(2));
f.get();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With