本文共 2818 字,大约阅读时间需要 9 分钟。
Intel TBB支持exceptions和cacellation。当Intel TBB算法里的代码抛出exception时,会发生下面的事情:
#include "tbb/tbb.h"#include#include using namespace tbb;using namespace std;vector Data;struct Update { void operator()( const blocked_range & r ) const { for( int i=r.begin(); i!=r.end(); ++i ) Data.at(i) += 1; }};int main() { Data.resize(1000); try { parallel_for( blocked_range (0, 2000), Update()); } catch( captured_exception& ex ) { cout << "captured_exception: " << ex.what() << endl; } catch( out_of_range& ex ) { cout << "out_of_range: " << ex.what() << endl; } return 0;}
parallel_for尝试迭代vector的2000个元素,但是里面只有1000个元素,因此在执行这个算法期间,表达式Data.at(i)抛出一个std::out_of_range,当exception发生时,算法取消并且在调用parallel_for时抛出一个exception。
为了取消算法,但是不抛出异常,使用表达式task::self().cancel_group_execution()。task::self参考Intel TBB task,调用cancel_group_execution()取消task_group_context里所有的任务,下一部将详细解释,如果它确实引起cancellation,那么方法返回true,如果task_group_context已经取消了,它返回false。
下面的例子展示怎样使用task::self().cancel_group_execution():
#include "tbb/tbb.h"#include#include using namespace tbb;using namespace std;vector Data;struct Update { void operator()( const blocked_range & r ) const { for( int i=r.begin(); i!=r.end(); ++i ) if( i
目前讨论的都是假设没有内部嵌套parallelism的情况,跳过task_group_context的细节,这部分介绍这2点。
Intel TBB算法通过创建一系列的task对象来执行的,默认情况下,这些task和task_group_context关联,且task_group_context由算法创建,取消一个task_group_context相当于取消所有子task_group_context对象。
exceptions向前传播,cancellation向后传播。例如,考虑下图的树状图,设想每个节点表示一个算法和一个task_group_context。
假设C节点上的算法抛出exception并且没有节点捕获这个exception,Intel TBB向前传播exception,向下取消相关子树的exception,如下:
如果你的代码在任何级别上捕获这个exception,那么Intel TBB不会向更远的方向传播。例如,一个exception不会逃离出一个parallel_for,那么parallel_for不会引起其他迭代的cancellation。
为了阻止向下传播cancellation,在stack上构造一个”isolated”task_group_context,并且显示的传递给这个算法,如下:
#include "tbb/tbb.h"bool Data[1000][1000];int main() { try { parallel_for( 0, 1000, 1, []( int i ) { task_group_context root(task_group_context::isolated); parallel_for( 0, 1000, 1, []( int j ) { Data[i][j] = true; }, root); throw "oops"; }); } catch(...) { } return 0;}
这个例子执行2个parallel循环,外部的循环在i上进行,内部的循环在j上进行,isolated的task_group_context root创建保护内部循环免受cacellation的干扰,当exception传播到外部循环,任何未使用的迭代会取消,但是内部循环不会取消,因此当程序结束时,Data每一行可能是不同的,但是在同一行里,元素会是全部的false或者true,而不是一个混合。