如何在c ++中实现函数的超时

New*_*bie 9 c++ time timeout c++11

我有功能f; 我想在启动f之后抛出异常1.我无法修改f().它可以在c ++中完成吗?

try {
   f();
}
catch (TimeoutException& e) {
//timeout
}
Run Code Online (Sandbox Code Playgroud)

Sme*_*eey 12

您可以创建一个单独的线程来运行调用本身,并在主线程中等待一个条件变量,f一旦它返回,它将由执行调用的线程发出信号.诀窍是等待条件变量1s超时,这样如果调用时间超过超时,你仍然会醒来,知道它,并且能够抛出异常 - 所有这些都在主线程中.这是代码(这里的现场演示):

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std::chrono_literals;

int f()
{
    std::this_thread::sleep_for(10s); //change value here to less than 1 second to see Success
    return 1;
}

int f_wrapper()
{
    std::mutex m;
    std::condition_variable cv;
    int retValue;

    std::thread t([&cv, &retValue]() 
    {
        retValue = f();
        cv.notify_one();
    });

    t.detach();

    {
        std::unique_lock<std::mutex> l(m);
        if(cv.wait_for(l, 1s) == std::cv_status::timeout) 
            throw std::runtime_error("Timeout");
    }

    return retValue;    
}

int main()
{
    bool timedout = false;
    try {
        f_wrapper();
    }
    catch(std::runtime_error& e) {
        std::cout << e.what() << std::endl;
        timedout = true;
    }

    if(!timedout)
        std::cout << "Success" << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 不会阻止`f()`运行。如果在第一次尝试退出f()之前再次运行f()线程安全吗?看起来这可能会带来更多问题。 (2认同)
  • OP 没有声明停止“f”是一个要求。重入/线程安全问题可以用这种方法解决,并进一步阐述——这里足以说明本质。 (2认同)

Ale*_*Che 9

您还可以使用std::packaged_task在另一个线程中运行您的函数 f() 。这个解决方案或多或少类似于这个,只是它使用标准类来包装。

std::packaged_task<void()> task(f);
auto future = task.get_future();
std::thread thr(std::move(task));
if (future.wait_for(1s) != std::future_status::timeout)
{
   thr.join();
   future.get(); // this will propagate exception from f() if any
}
else
{
   thr.detach(); // we leave the thread still running
   throw std::runtime_error("Timeout");
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以尝试将其包装到函数模板中,以允许在超时时调用任意函数。类似的东西:

template <typename TF, typename TDuration, class... TArgs>
std::result_of_t<TF&&(TArgs&&...)> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
    using R = std::result_of_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");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用:

void f1() { ... }
call_with_timeout(f1, 5s);

void f2(int) { ... }
call_with_timeout(f2, 5s, 42);

int f3() { ... }
int result = call_with_timeout(f3, 5s);
Run Code Online (Sandbox Code Playgroud)

这是一个在线示例:http : //cpp.sh/7jthw