5

有没有办法在 std::async 方法中实现超时,所以如果线程在指定的时间内没有完成,我希望这个调用超时并完成。我怎样才能实现这个功能。

4

2 回答 2

6

没有(标准)方法可以进入线程并杀死它,无论如何这通常是一个坏主意。更简洁的选择是将开始时间和最大持续时间传递给函数,然后(可能随着计算的进行多次)检查当前时间减去开始时间是否太长。

我会做这样的事情:

#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

短运行线程超时
短运行函数完成
长时间运行线程正在工作
长时间运行线程超时
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程正在工作
长时间运行线程超时
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的线程正在工作
长时间运行的功能已完成

于 2013-01-07T21:04:50.253 回答
6

该标准没有提供任何非合作终止线程的方法。缺少自动超时功能只是另一个例子。

相反,您必须实现您传递给的代码以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();
于 2013-01-07T21:02:25.113 回答