C++ 为 class 方法实现超时函数模板

C++ Implementing a timeout function template for class methods

我想实现的目标是让程序停止进程,如果进程超过超时时间return超时错误。

我从 得到了超时功能。我 运行 遇到一个错误,指出 std::result_of_t 在 c++17 中已被弃用,所以我使用建议的替换 std::invoke_result_t 重新创建它并像这样实现它:

template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
    using R = std::invoke_result_t<TF&&, TArgs&&...>;
    std::packaged_task<R(TArgs...)> task(f);
    auto future = task.get_future();
    std::thread thr(std::move(task), std::forward<TArgs>(args)...);
    if (future.wait_for(timeout) != std::future_status::timeout)
    {
       thr.join();
       return future.get(); // this will propagate exception from f() if any
    }
    else
    {
       thr.detach(); // we leave the thread still running
       throw std::runtime_error("Timeout");
    }
}

我想用它来检查 class 方法函数的超时。所以我尝试以类似于以下的方式使用它:

template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> ClassOne::run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
    using R = std::invoke_result_t<TF&&, TArgs&&...>;
    std::packaged_task<R(TArgs...)> task(f);
    auto future = task.get_future();
    std::thread thr(std::move(task), std::forward<TArgs>(args)...);
    if (future.wait_for(timeout) != std::future_status::timeout)
    {
       thr.join();
       return future.get(); // this will propagate exception from f() if any
    }
    else
    {
       thr.detach(); // we leave the thread still running
       throw std::runtime_error("Timeout");
    }
}

// The function checked for timeout
int ClassOne::func(ClassTwo *param1, std::string name)
{
    // Some code here...

    // For mimicking function process:
    std::this_thread::sleep_for(10s);
    return 0;
}

// Function which calls the timed process with timeout function
int ClassOne::dummy(ClassTwo *param1, std::string name)
{
    int retVal = 0; // zero for no error, non-zero for error
    try
    {
        retVal = run_with_timeout(func, 20s, param1, name);
    }
    catch (runtime_error & e)
    {
        return 1;
    }
}

有了这个,我得到了错误:

no instance of function template "ClassOne::run_with_timeout" matches the argument list
    argument types are: (int (ClassTwo *param1, std::string target), std::chrono::seconds, ClassTwo *, std::string)

我认为问题与 this entry 类似,但我不知道如何更正它。我需要使用超时函数的一些函数具有不同的对象参数,这就是使用函数模板的原因。

非常感谢您的帮助!

顾名思义,std::invoke_result_t是应用std::invoke的结果类型。我在这里突出显示了适用于您的情况:

INVOKE(f, t1, t2, ..., tN) is defined as follows:
...
If f is a pointer to member function of class T:

  • If std::is_base_of<T, std::decay_t<decltype(t1)>>::value is true, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.*f)(t2, ..., tN)
  • If t1 does not satisfy the previous items, then INVOKE(f, t1, t2, ..., tN) is equivalent to ((*t1).*f)(t2, ..., tN).

所以你的电话应该是:

retVal = run_with_timeout(&ClassOne::func, 20s, this, std::move(param1), std::move(name));

编辑:我花了整整 20 分钟才让它真正起作用。如上所述添加 std::move 或通过 const 引用(在 dummy 中)获取 name 使其编译。我想不出 param1 的类似转换。我很想知道那个错误背后的原因,但至少你眼前的问题已经解决了。