并发编程高性能计算【免费下载链接】oneTBBoneAPI Threading Building Blocks (oneTBB)项目地址https://gitcode.com/gh_mirrors/on/oneTBB点击查看免费下载tagged_msg是 oneTBB 流图flow graph中用于携带运行时类型消息的类模板它由**一个标签tag与一个消息值value**组成其中消息值可以是模板参数包TN中任意一个已定义类型。本文以 tagged_msg 官方参考文档 为核心骨架结合 oneTBB 仓库中的实际实现_flow_graph_types_impl.h、异常处理代码_exception.h、exception.cpp与单元测试test_tagged_msg.cpp完整讲解该类型的声明、构造、访问接口、底层存储机制与典型使用场景如indexer_node的输出帮助读者在异构消息流图中安全、高效地进行类型识别与取值。一、tagged_msg 是什么在 oneTBB 流图中消息message通常在编译期就确定了类型。但在某些场景下一条消息需要在运行时才决定自己到底是多种候选类型中的哪一种。tagged_msg正是为这种需求设计的它是一个标签 值的组合体标签用于标识当前存储的是哪一种类型值则真正携带数据。文档对它的定位是A class template composed of a tag and a message. The message is a value that can be one of several defined types. 一个由标签和消息组成的类模板。消息可以是若干已定义类型之一的值。在流图中tagged_msg最典型的使用位置是作为indexer_node的输出类型——indexer_node把多个输入端口收到的不同类型消息汇聚成一条tagged_msg输出下游节点再通过is_a/cast_to判断并取出实际值。类模板声明// 定义于头文件 oneapi/tbb/flow_graph.h namespace oneapi { namespace tbb { namespace flow { templatetypename TagType, typename... TN class tagged_msg { public: templatetypename T, typename R tagged_msg(T const index, R const val); TagType tag() const; templatetypename V const V cast_to() const; templatetypename V bool is_a() const; }; } // namespace flow } // namespace tbb } // namespace oneapi模板参数约束Requirements文档明确给出了两个硬性约束违反任何一个都会导致编译错误模板参数包TN中的所有类型都必须满足 ISO C 标准 [copyconstructible] 章节中的CopyConstructible要求——因为tagged_msg内部需要对值做拷贝构造复制存储不可拷贝的类型无法作为候选类型。TagType必须是无符号整型integral unsigned type例如size_t、unsigned、unsigned char、char当char无符号时也可用。测试代码中就使用了tagged_msgchar, int, char, double这样以char作为标签类型的实例见 test_tagged_msg.cpp。二、成员函数详解tagged_msg对外暴露四个核心成员函数一个构造函数、一个标签访问函数、以及一对类型判断/类型取值函数。2.1 构造函数tagged_msg(T const index, R const value)templatetypename T, typename R tagged_msg(T const index, R const value);构造一个标签为index、值为val的tagged_msg。其约束条件为R必须与TN中的某一个类型完全相同不能是能隐式转换的类型必须是精确匹配T必须可作为TagType的构造函数参数即能够隐式转换为TagType。例如// tag 为 size_t值类型为 int tbb::flow::tagged_msgsize_t, int, double m1(1, 3); // tag 为 size_t值类型为 double tbb::flow::tagged_msgsize_t, int, double m2(3, 8.0);2.2 标签查询TagType tag() const返回当前存储的标签。标签不参与类型识别仅作为消息的附加标识可供上层业务逻辑使用。测试中演示了标签的读取与修改set_tagCHECK_MESSAGE( (j.tag() 2), Error retrieving tag for j); j.set_tag(10); CHECK_MESSAGE( (j.tag() 10), Error updating tag for j);注意set_tag是tagged_msg实现的补充接口见_flow_graph_types_impl.h虽然参考文档正文未列出但它与tag()配套使用可修改已有消息的标签。2.3 类型转换templatetypename V const V cast_to() const返回存储值的const 引用要求V必须是TN中的某个类型。关键行为如果实际存储值的类型就是V则返回该值的 const 引用如果实际存储值的类型不是V则抛出std::runtime_error异常。从实现看该调用最终进入variant::variant_cast_toU()在类型不匹配时通过throw_exception(exception_id::bad_tagged_msg_cast)抛出异常见_flow_graph_types_impl.h而exception_id::bad_tagged_msg_cast在_exception.h中定义最终在exception.cpp中被转换为消息为Illegal tagged_msg cast的std::runtime_errorcase exception_id::bad_tagged_msg_cast: DO_THROW(std::runtime_error, (Illegal tagged_msg cast)); break;测试代码验证了异常行为见 test_tagged_msg.cpptry { double y cast_todouble(i); // i 实际存的是 int CHECK_MESSAGE( (false (0 ! y)), Error: cast to type in tuple did not get exception); } catch(std::runtime_error bc) { CHECK_MESSAGE( (0 strcmp(bc.what(), Illegal tagged_msg cast)), Incorrect std:runtime_error); }2.4 类型判断templatetypename V bool is_a() const返回true当且仅当V就是tagged_msg当前持有的值类型否则返回false。与cast_to不同is_a不会抛异常它是安全尝试的前提tagged_msg_type double_tagged_msg(3, 8.0); CHECK_MESSAGE( (is_adouble(double_tagged_msg)), Wrong type ( double)); CHECK_MESSAGE( (!is_achar(double_tagged_msg)), Wrong type (! char)); CHECK_MESSAGE( (!is_aint(double_tagged_msg)), Wrong type (! int));推荐的安全取值模式是先is_aV()判断再cast_toV()取值从而避免异常路径。三、自由函数形式的 cast_to 与 is_a除了成员函数tagged_msg还配套提供两个非成员模板函数便于在泛型上下文如模板函数内部中书写templatetypename V, typename T const V cast_to(T const t) { return t.cast_toV(); } templatetypename V, typename T bool is_a(T const t);约束条件T必须是tagged_msg类模板的一个实例化类型V必须与tagged_msg对应的某个模板参数即TN中的某一项相同。文档明确说明这两个自由函数作用于tagged_msg对象时与直接调用其成员函数完全等价。从实现看见_flow_graph_types_impl.h它们只是简单转发templatetypename V, typename T const V cast_to(T const t) { return t.template cast_toV(); } templatetypename V, typename T bool is_a(T const t) { return t.template is_aV(); }在类型本身也是模板参数的场景例如编写通用流图节点处理函数中t.template cast_toV()的显式template关键字写法比较繁琐自由函数可以把调用简化为cast_toV(t)。四、源码级实现变体存储variant背后的机制要真正理解tagged_msg的行为值得深入其内部实现。核心实现在_flow_graph_types_impl.h中整体思路是Tuple与编译期类型检查tagged_msg内部用std::tupleTN...记录候选类型通过is_element_of等模板元编程工具在编译期校验传入值类型必须是候选类型之一对应文档R必须与TN中某一类型相同的约束。variant内部类真正的值存储在一个手写的轻量变体variant中。它不像std::variant那样为每个类型分配固定大小空间而是通过pick_tuple_max在编译期找出候选类型中对齐要求最大的类型AlignType与体积最大的类型MaxSizeType以aligned_spaceAlignType, MaxNElements申请一块同时满足大小与对齐要求的未类型化内存my_space通过 placement new 将实际值构造进这块内存见_flow_graph_types_impl.h。WrapperT类型擦除每个候选类型都被包装成继承自WrapperBase的WrapperT含数组特化WrapperT[N]利用WrapperBase的虚函数CopyTo实现拷贝利用dynamic_cast实现运行时类型识别。这正是is_a/cast_to的底层支撑variant_is_aU()对WrapperBase*做dynamic_castconst WrapperU*非空即为类型匹配variant_cast_toU()同样做dynamic_cast失败则抛出bad_tagged_msg_cast异常见_flow_graph_types_impl.h。默认构造状态tagged_msg()默认构造函数把标签置为TagType(~0)全 1 位并构造一个特殊的default_constructed包装器表示未持有真实值is_default_constructed()可查询该状态见_flow_graph_types_impl.h。测试中大量使用了这一机制来验证赋值/析构过程中的对象生命周期计数CheckTypeint::check_type_counter。由此可见tagged_msg在类型固定、数量有限的前提下提供了一种零动态分配内存内嵌于对象内部的运行时多态方案代价是值的读取只能获得 const 引用且cast_to失败走异常路径。五、与 indexer_node 的组合使用tagged_msg在流图中最重要的应用是作为indexer_node的输出类型。indexer_nodeT0, T1, ...的多个输入端口可以接收不同类型的消息并将其打包为tagged_msgsize_t, T0, T1, ...输出。仓库中的test_indexer_node.cpp大量验证了这种组合例如typedef tbb::flow::indexer_nodeT0, T1, T2, T3, T4, T5, T6, T7, T8, T9 indexer_node_type;conformance_composite_node.cpp中也把tagged_msg作为复合节点的输出类型之一见 conformance_composite_node.cppusing OutputTupleType std::tupletbb::flow::continue_msg, std::tupleint, int, oneapi::tbb::flow::tagged_msgsize_t, int, float, ...;典型的消费端模式是tbb::flow::function_nodeindexer_nodeint, float::output_type consumer(g, 1, [](const auto msg) { if (msg.is_aint()) { int v msg.cast_toint(); // 安全先 is_a 再 cast_to // ... } else if (msg.is_afloat()) { float v msg.cast_tofloat(); // ... } });六、实战要点与注意事项综合文档与测试使用tagged_msg时有以下要点候选类型必须精确匹配cast_toV/is_aV中的V以及构造时的值类型R都必须与TN中的类型完全相同。测试特意验证了is_aCheckTypeint*对数组类型counted_array_type返回false见 test_tagged_msg.cpp说明指针、数组等近似类型不会被误判为匹配。支持数组类型tagged_msg可以存储固定大小的 C 数组如char[15]并通过专门的数组Wrapper特化做逐元素构造与析构见_flow_graph_types_impl.h。测试覆盖了odd_array_type、i_vector_array等数组/非 POD 数组场景。异常路径类型不匹配的cast_to会抛出what()为Illegal tagged_msg cast的std::runtime_error若编译时关闭异常支持TBB_USE_EXCEPTIONS未定义相关行为在测试中被条件编译跳过。返回的是 const 引用cast_toV只允许读取不允许修改内部值——这是有意设计因为变体存储无法安全地原地替换类型。标签的语义标签由使用者自行约定如枚举端口序号、协议号等tagged_msg本身不校验标签与值类型的对应关系它只负责携带标签。七、测试验证与进一步阅读该特性由 test/tbb/test_tagged_msg.cpp 专门测试文件头注释明确标注其对应规范条目[flow_graph.tagged_msg]并通过两个TEST_CASE分别覆盖TestWrapper底层Wrapper的构造、拷贝、数组与容器类型支持RunTestsis_a/cast_to/tag/ 默认构造状态、赋值、异常抛出与对象生命周期计数等完整行为。测试目标同时被登记在 test/CMakeLists.txttest_tagged_msg随TBB::tbb依赖一起构建运行。若需继续深入可参考tagged_msg 参考文档indexer_node 类模板参考文档核心实现_flow_graph_types_impl.h异常枚举定义_exception.h异常到 std::runtime_error 的映射exception.cppindexer_node 测试test_indexer_node.cpp总而言之tagged_msg为 oneTBB 流图提供了编译期确定候选类型集合、运行期确定实际类型的消息表达能力。理解它的接口约束与底层变体存储机制是在indexer_node等多类型汇聚场景下写出健壮、高效流图代码的关键一步。赞分享并发编程高性能计算【免费下载链接】oneTBBoneAPI Threading Building Blocks (oneTBB)项目地址https://gitcode.com/gh_mirrors/on/oneTBB点击查看免费下载相关推荐Sunshine 常见问题排查指南14 类症状从黑屏到丢包的修复手册Sunshine 常见问题排查指南14 类症状从黑屏到丢包的修复手册 Sunshine 是面向 Moonlight 客户端的自托管游戏串流服务端实际使用中黑音视频后端oneTBB flow graph 中的 indexer_node异构多输入消息汇聚与 tagged_msg 使用指南oneTBB flow graph 中的 indexer_node异构多输入消息汇聚与 tagged_msg 使用指南 indexer_node 是 oneA并发编程高性能计算Reticulum 分布式开发用 rngit 在加密网络上重建主权化的 Git 协作基础设施Reticulum 分布式开发用 rngit 在加密网络上重建主权化的 Git 协作基础设施 导读 本文以 docs/markdown/distributed并发编程高性能计算上一篇Cytoscape.js 核心事件 API深入掌握 cy.one() 一次性事件监听下一篇wired-fab 组件实战手绘风格浮动操作按钮FAB的使用与底层实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考