/*
Warning: parallel_for does NOT copy thread local
states from the current thread to the worker threads.
This means for example that Tensor operations CANNOT be used in the
body of your function, **only data pointers**.
*/
template <class F>
inline void parallel_for(
const int64_t begin,
const int64_t end,
const int64_t grain_size,
const F& f);
从 parallel_for 的注释中知道在并行区域中只能使用data pointer,其异常处理通过 std::exception_ptr
实现。
# https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/ParallelOpenMP.h
template <typename F>
inline void invoke\_parallel(
int64\_t begin,
int64\_t end,
int64\_t grain\_size,
const F& f) {
...
std::exception_ptr eptr;
#pragma omp parallel
{
...
if (begin_tid < end) {
try {
internal::ThreadIdGuard tid\_guard(tid);
f(begin_tid, std::min(end, chunk_size + begin_tid));
} catch (...) {
if (!err_flag.test_and_set()) {
eptr = std::current_exception();
}
}
}
}
if (eptr) {
std::rethrow_exception(eptr);
}
}
std::exception_ptr
std::exception_ptr
是一个可空的 pointer-like 类型,它管理一个由std::current_exception
捕获的异常对象。std::exception_ptr
的实例可以传递给另一个函数,可能是在另一个线程上,该异常可以被重新抛出并使用catch子句处理。
默认构造的std::exception_ptr
是空指针;它不指向异常对象。
std::exception_ptr
的两个实例只有当它们都为空或都指向同一个异常对象时才相等。
std::exception_ptr
不能隐式转换为任何算术、枚举或指针类型。它可根据上下文条件下转换为bool,如果为null
,则计算为false
,否则为true
。
std::exception_ptr
引用的异常对象只要至少有一个std::exception_ptr
引用它,它就仍然有效。这是对通常的异常对象生命周期规则的补充)
std::exception_ptr
满足NullablePointer
的要求。
std::make_exception_ptr
template< class E >
std::exception\_ptr make\_exception\_ptr( E e ) noexcept;
创建一个std::exception_ptr
,它持有e副本的引用。这就像执行以下代码一样:
try {
throw e;
} catch(...) {
return std::current_exception();
}
std::current_exception
std::exception\_ptr current\_exception() noexcept;
如果在异常处理期间调用(通常是在catch
子句中),则捕获当前异常对象并创建一个std::exception_ptr
,该std::exception_ptr
包含该异常对象的副本或引用(取决于实现)。被引用的对象至少只要有一个引用它的exception_ptr
对象,它就仍然有效。
如果该函数的实现需要调用new并且调用失败,则返回的指针将保存对std::bad_alloc
实例的引用。
如果此函数的实现需要复制捕获的异常对象,并且其复制构造函数抛出异常,则返回的指针将持有对所抛出异常的引用。如果抛出异常对象的复制构造函数也抛出异常,则返回的指针可以持有对std::bad_exception
实例的引用,以中断循环。
如果在不处理异常的情况下调用函数,则返回一个空的std::exception_ptr
。
std::rethrow_exception
[[noreturn]] void rethrow\_exception( std::exception\_ptr p );
抛出异常指针p引用的先前捕获的异常对象,或该对象的副本。
如果p为空,则行为未定义。
Example
#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>
void handle\_eptr(std::exception\_ptr eptr) // passing by value is ok
{
try {
if (eptr) {
std::rethrow_exception(eptr);
}
} catch(const std::exception& e) {
std::cout << "Caught exception \"" << e.what() << "\"\n";
}
}
int main()
{
std::exception_ptr eptr;
try {
std::string().at(1); // this generates an std::out\_of\_range
} catch(...) {
eptr = std::current_exception(); // capture
}
handle_eptr(eptr);
} // destructor for std::out\_of\_range called here, when the eptr is destructed
参考文献
- https://en.cppreference.com/w/cpp/error/exception\_ptr
- https://en.cppreference.com/w/cpp/error/make\_exception\_ptr
- https://en.cppreference.com/w/cpp/error/current\_exception
- https://en.cppreference.com/w/cpp/error/rethrow\_exception