我要调用的方法foo()
超时(例如1分钟)。如果执行时间少于1分钟,则返回结果。否则将引发异常。这是代码:
//PRINT "START" IN THE LOG
auto m = std::make_shared<std::mutex>();
auto cv = std::make_shared<std::condition_variable>();
auto ready = std::make_shared<bool>(false);
auto response = std::make_shared<TResponse>();
auto exception = std::make_shared<FooException>();
exception->Code = ErrorCode::None;
std::thread([=]
{
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [=]{ return *ready; });
try
{
//PRINT "PROCESS" IN THE LOG
auto r = foo();
*response = std::move(r);
}
catch(const FooException& e)
{
*exception = std::move(e);
}
lk.unlock();
cv->notify_one();
}).detach();
std::unique_lock<std::mutex> lk(*m);
*ready = true;
cv->notify_one();
auto status = cv->wait_for(lk, std::chrono::seconds(60));
if (status == std::cv_status::timeout)
{
//PRINT "TIMEOUT" IN THE LOG
//throw timeout exception
}
else
{
//PRINT "FINISH" IN THE LOG
if (exception->Code == ErrorCode::None)
{
return *response;
}
else
{
throw *exception;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以看到我在代码中添加了日志START / PROCESS / FINISH / TIMEOUT,每次执行此方法时,我都可以在日志中看到START / PROCESS / FINISH或START / PROCESS / TIMEOUT模式。但是,有时日志是START / PROCESS,没有任何完成/超时。我认为cv->wait_for
最多应将当前线程阻塞60秒,然后它以TIMEOUT或FINISH存在。
该foo()
方法包含对网络驱动器的磁盘IO操作,该操作有时会挂起1多个小时(原因与该问题无关,现在无法解决),我尝试foo
用线程睡眠代替,一切正常预期。该代码有什么问题,我该如何改进?
由于调用中没有谓词cv->wait_for
,因此线程可能会被虚假地解除阻塞。不过奇怪的是没有打印FINISH/TIMEOUT。因此,我们可能需要更多信息:该程序会发生什么?它是否挂起、是否抛出、是否直接退出、是否在之后的行中打印cv->wait_for
?
您可以尝试使用std::async
并查看是否出现相同的行为(此外,它将大大简化您的代码):
std::future<int> res = std::async(foo);
std::future_status stat = res.wait_for(std::chrono::seconds(60));
if (stat != std::future_status::ready) {
std::cout << "Timed out..." << "\n";
} else {
try {
int result = res.get();
std::cout << "Result = " << result << std::endl;
} catch (const FooException& e) {
std::cerr << e.what() << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
编辑正如析构函数中块CuriouslyRecurringThoughts
的未来的评论中所指出的。std::async
如果这不是一个选项,则以下代码将使用一个std::promise
和一个分离线程:
std::promise<int> prom;
std::future<int> res = prom.get_future();
std::thread([p = std::move(prom)]() mutable {
try {
p.set_value(foo());
} catch (const std::exception& e) {
p.set_exception(std::current_exception());
}
}).detach();
Run Code Online (Sandbox Code Playgroud)
等待完成std::future
如前所示。