我有功能f; 我想在启动f之后抛出异常1。 我无法修改f()。它可以在c ++中完成吗?
try {
f();
}
catch (TimeoutException& e) {
//timeout
}
答案 0 :(得分:8)
您可以创建一个单独的线程来运行调用本身,并在主线程中等待一个条件变量,一旦它返回,它将由执行f
调用的线程发出信号。诀窍是等待条件变量1s超时,这样如果调用时间超过超时,你仍然会醒来,知道它,并且能够抛出异常 - 全部在主线程中。这是代码(现场演示here):
#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;
}
答案 1 :(得分:1)
您可以创建一个新线程并异步等待1s传递,然后抛出异常。但是,异常只能在它们被抛出的同一个线程中被捕获,因此,您无法捕获调用f()
的同一个线程,就像在示例代码中一样 - 但不是一个规定的要求,所以对你来说可能没问题。
只有当f
保证在少于1秒内返回时,才能同步执行此操作:
f()
但可能很难证明f
确实及时回归。
答案 2 :(得分:0)
您还可以使用std::packaged_task在另一个线程中运行函数f()。此解决方案与this差不多,只是它使用标准类来包装。
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)
future.get(); // this will propagate exception from f() if any
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
答案 3 :(得分:0)
这基于 Smeehee 的示例,如果您需要一个接受可变数量参数的示例(另请参阅 https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_thread_timeout_template/README.md)
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int my_function_that_might_block(int x)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
return 1;
}
template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;
template<typename ret, typename T, typename... Rest>
ret wrap_my_slow_function(fn<ret, T, Rest...> f, T t, Rest... rest)
{
std::mutex my_mutex;
std::condition_variable my_condition_var;
ret result = 0;
std::unique_lock<std::mutex> my_lock(my_mutex);
//
// Spawn a thread to call my_function_that_might_block().
// Pass in the condition variables and result by reference.
//
std::thread my_thread([&]()
{
result = f(t, rest...);
// Unblocks one of the threads currently waiting for this condition.
my_condition_var.notify_one();
});
//
// Detaches the thread represented by the object from the calling
// thread, allowing them to execute independently from each other. B
//
my_thread.detach();
if (my_condition_var.wait_for(my_lock, std::chrono::seconds(1)) ==
std::cv_status::timeout) {
//
// Throw an exception so the caller knows we failed
//
throw std::runtime_error("Timeout");
}
return result;
}
int main()
{
// Run a function that might block
try {
auto f1 = fn<int,int>(my_function_that_might_block);
wrap_my_slow_function(f1, 42);
//
// Success, no timeout
//
} catch (std::runtime_error& e) {
//
// Do whatever you need here upon timeout failure
//
return 1;
}
return 0;
}