有没有办法在 std::async 方法中实现超时,所以如果线程在指定的时间内没有完成,我希望这个调用超时并完成。我怎样才能实现这个功能。
2 回答
没有(标准)方法可以进入线程并杀死它,无论如何这通常是一个坏主意。更简洁的选择是将开始时间和最大持续时间传递给函数,然后(可能随着计算的进行多次)检查当前时间减去开始时间是否太长。
我会做这样的事情:
#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;
};
这个简单的实用程序跟踪开始时间和最大持续时间(并提供一种指定无穷大的方法),并允许用户查询简单的事实,最重要的是是否发生了超时。
下面测试;您可以通过定义/取消定义来添加假延迟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();
}
一种可能的输出为FAKE_DELAY
off:
短期运行功能完成
短期运行功能完成
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程正在工作
长期运行线程工作
长时间运行 线程工作
长时间运行功能完成
长时间运行线程工作
长时间运行线程工作
长时间运行线程工作
长时间运行线程工作
长时间运行线程工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行功能完成
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作长时间运行线程正在 长时间
工作
正在运行的线程正在
运行 长时间运行的线程正在运行 长时间运行
的线程正在
运行 长时间运行的线程正在运行
长时间运行的线程正在运行
长时间运行的线程正在运行
长时间运行的功能完成
一种可能的输出FAKE_DELAY
on:
短运行线程超时
短运行函数完成
长时间运行线程正在工作
长时间运行线程超时
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程超时
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的功能已完成
该标准没有提供任何非合作终止线程的方法。缺少自动超时功能只是另一个例子。
相反,您必须实现您传递给的代码以std::async
协同处理此操作。协作杀死线程的一种模式是向函数传递一个对象,该对象提供了一种方法来检查异步函数是否应该继续,如果不继续,则抛出异常。
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();