std :: async中的超时

时间:2013-01-07 20:33:10

标签: c++ c++11 std stdthread stdasync

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

2 个答案:

答案 0 :(得分: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 关闭的一个可能输出:

  

短跑功能完成
  短期运行功能完成
  长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行功能完成
  长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行功能完成
  长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行功能完成

上的FAKE_DELAY 的一个可能输出:

  

短跑线程用完了时间
  短期运行功能完成
  长时间运行的线程正在工作中   长时间运行的线程用完了   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程用完了   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行的线程正在工作中   长时间运行功能完成

答案 1 :(得分:5)

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

相反,您必须实现传递给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();