gpt4 book ai didi

c++ - 并发::任务析构函数导致调用在有效用例中中止

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:39:27 25 4
gpt4 key购买 nike

你能告诉我我用来处理用例的方法是否无效吗?如果是,正确的处理方法是什么:

task<int> do_work(int param)
{
// runs some work on a separate thread, returns task with result or throws exception on failure
}

void foo()
{
try
{
auto result_1 = do_work(10000);
auto result_2 = do_work(20000);

// do some extra work

process(result_1.get(), result_2.get());
}
catch (...)
{
// logs the failure details
}
}

因此代码尝试并行执行两个作业,然后处理结果。如果其中一个作业抛出异常,则调用 task::get 将重新抛出异常。如果两个任务都抛出异常,则会出现此问题。在这种情况下,对 task::get 的第一次调用将导致堆栈展开,因此将调用第二个 task 的析构函数,进而导致另一个异常在堆栈展开期间重新抛出,这会导致调用“中止”。

在我遇到这个问题之前,这种方法对我来说似乎完全有效。

最佳答案

简而言之,您有一个未处理(未观察到)的异常,因为在您的一项任务中抛出的异常没有得到 caught by the task, one of its continuations, or the main app ,因为从 task::get 为第一个任务重新抛出的异常会在第二个任务调用 task::get 之前展开堆栈。

更简化的代码显示 std::terminate 被调用是因为任务中抛出的异常没有得到处理。取消注释 result.get() 将阻止调用 std::terminate,因为 task::get 将重新抛出异常。

#include <pplx/pplx.h>
#include <pplx/pplxtasks.h>
#include <iostream>

int main(int argc, char* argv[])
{
try
{
auto result = pplx::create_task([] ()-> int
{
throw std::exception("task failed");
});

// actually need wait here till the exception is thrown, e.g.
// result.wait(), but this will re-throw the exception making this a valid use-case

std::cout << &result << std::endl; // use it
//std::cout << result.get() << std::endl;
}
catch (std::exception const& ex)
{
std::cout << ex.what() << std::endl;
}

return 0;
}

查看 pplx::details::_ExceptionHandler::~_ExceptionHolder() 中的建议

//pplxwin.h
#define _REPORT_PPLTASK_UNOBSERVED_EXCEPTION() do { \
__debugbreak(); \
std::terminate(); \
} while(false)


//pplxtasks.h
pplx::details::_ExceptionHandler::~_ExceptionHolder()
{
if (_M_exceptionObserved == 0)
{
// If you are trapped here, it means an exception thrown in task chain didn't get handled.
// Please add task-based continuation to handle all exceptions coming from tasks.
// this->_M_stackTrace keeps the creation callstack of the task generates this exception.
_REPORT_PPLTASK_UNOBSERVED_EXCEPTION();
}
}

在原始代码中,对 task::get 的第一次调用引发了该任务中抛出的异常,这显然阻止了对 task::get 的第二次调用,因此第二个任务的异常没有得到处理(保持“未观察到”)。

the destructor of the second task will be called and will in turn cause one more exception to be re-thrown during stack unwind which causes 'abort' to be called.

第二个任务的析构函数不会重新抛出它只是调用 std::terminate()(它调用 std::abort())的异常

看。 Exception Handling in the Concurrency Runtime

关于c++ - 并发::任务析构函数导致调用在有效用例中中止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24559197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com