恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

mold 仓库内嵌 oneTBB 指南:深入理解 Flow Graph 的 Graph Object(图对象)与整图操作

  • 首页
  • 资讯中心
  • /
  • mold 仓库内嵌 oneTBB 指南:深入理解 Flow Graph 的 Graph Object(图对象)与整图操作

相关资讯

骨龄识别GUI开发:ONNX轻量化+PyQt5医学图像处理 2026/9/15 16:16:05
Seerr 邮件通知配置完全指南:SMTP、TLS 加密与 OpenPGP 签名详解 2026/9/15 16:11:05
Paper:高性能 Minecraft 服务端项目实战指南 2026/9/15 16:11:05

最新资讯

从Chimera到ChimeraX:结构生物学可视化迁移实战指南
Boss直聘数据爬取与可视化分析:从requests到pyecharts完整实战
AWS CLI 实战:用 cloudformation estimate-template-cost 快速估算模板月度成本
Instructor 多 Provider 结构化输出集成指南:从 OpenAI 到 Ollama 的统一接入方案
ET 框架单线程异步原理:从回调式计时器到 await 与 ETTask
Raspberry Pi 距离检测实战:在 IoT-For-Beginners 中驱动 VL53L0X 飞行时间传感器

今日推荐

GDPR下大数据架构重构与隐私保护实践
多组学数据平台架构设计与优化实践
企业主数据管理系统架构设计与实施全解析

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

mold 仓库内嵌 oneTBB 指南:深入理解 Flow Graph 的 Graph Object(图对象)与整图操作

发布时间:2026/9/15 16:16:05
mold 仓库内嵌 oneTBB 指南:深入理解 Flow Graph 的 Graph Object(图对象)与整图操作 mold 仓库内嵌 oneTBB 指南深入理解 Flow Graph 的 Graph Object图对象与整图操作【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold导读本文聚焦 oneTBBoneAPI Threading Building Blocks数据流编程中最为基础的抽象——Flow Graph 的 Graph Object图对象。图对象是一个图中所有节点与边的集合容器也是触发wait_for_all等待完成、reset重置状态与cancel取消执行三类整图级操作的唯一入口。在 mold 仓库的 third-party/tbb 第三方依赖中读者将掌握图对象的正确构造方式、生命周期管理要点、三类整图操作的使用时机以及由源码佐证其底层实现从而写出不会因图销毁时序错误而崩溃的 oneTBB 数据流程序。一、图对象是什么Flow Graph 的集合容器在 oneTBB 的 Flow Graph 接口中概念上一个流图flow graph就是节点node与边edge的集合每个节点恰好属于一个图each node belongs to exactly one graph边只能在同一个图的节点之间建立edges are made only between nodes in the same graph。而**图对象graph object**就是这个节点与边集合的代表它承担两类职责持有集合作为节点与边所属的容器存在整图操作入口对整张图执行统一操作包括——wait_for_all()等待与图相关的所有任务完成reset()重置图中所有节点的状态cancel()取消图中所有节点的执行。从源码结构看oneTBB 的graph类定义于 third-party/tbb/include/oneapi/tbb/detail/_flow_graph_impl.h它继承自no_copy与graph_proxy即图对象不可拷贝只能按值存在于单一作用域并通过引用传递。同文件中还可看到graph_iterator、graph_task_list等辅助类型以及graph_node基类L465-L490印证了图—节点的层级关系。最基础的图对象使用方式如下graph g; g.wait_for_all();由于这是一个没有任何节点和边的平凡图trivial graph没有任务被派生因此wait_for_all会立即返回。但正是这样一行代码构成了所有 oneTBB 数据流程序的骨架先构造图再向图中添加节点与边最后等待整图完成。二、wait_for_all等待整图任务完成wait_for_all是图对象最核心的方法。它在graph类中的声明位于 _flow_graph_impl.h语义为阻塞直到该图派生的所有任务执行完毕。它的重要性体现在两个层面同步计算进度等待计算结果就绪后再继续主线程逻辑销毁前置条件在销毁图对象或其任何节点之前必须调用否则程序可能崩溃。oneTBB 官方用户指南 always_use_wait_for_all 专门用一个反例说明了遗忘wait_for_all的后果void no_wait_for_all() { graph g; function_node int, int f( g, 1, []( int i ) - int { return spin_for(i); } ); f.try_put(1); // program will fail when f and g are destroyed at the // end of the scope, since the body of f is not complete }崩溃机理在上面的函数中f.try_put(1)会派生一个任务去执行节点f的 body但当函数作用域结束时g和f被销毁而该任务仍在飞行中in flight。任务完成后会回头查找它的后继节点successor此时图与节点都已经被删除造成悬空访问。在函数末尾补上g.wait_for_all()即可避免对图与节点的过早销毁。排查建议如果在使用 Flow Graph 时出现神秘行为mysterious behavior第一件事就是检查是否调用了wait_for_all。三、reset重置整图状态当需要复用同一张图执行新一轮计算时可以使用reset方法。其声明为void reset(reset_flags f rf_reset_protocol);见 _flow_graph_impl.h。它默认使用rf_reset_protocol标志用于重置图内各节点的协议状态例如function_node内部缓冲区与执行计数使图恢复到可重新喂入消息的状态。对应地每个节点通过纯虚函数reset_node(reset_flags f)见同文件 L489参与整图重置这体现了图对象发起、节点各自执行的分发机制。注意reset与wait_for_all的使用顺序有讲究——一般应先wait_for_all确保上一轮任务全部结束再reset后开启下一轮避免新旧两轮任务交错。四、cancel取消整图执行cancel方法_flow_graph_impl.h用于无异常地取消整张图的执行。取消语义如下已经开始执行的节点会执行到完成尚未开始执行的节点将不再启动。官方指南 cancel_a_graph 给出了两种取消方式。方式一外部显式取消构造图时传入一个显式的task_group_context随后从外部调用其cancel_group_execution()task_group_context t; graph g(t); function_node int, int f1( g, 1, []( int i ) { return i; } ); function_node int, int f2( g, 1, []( const int i ) - int { cout Begin i \n; spin_for(0.2); cout End i \n; return i; } ); function_node int, int f3( g, 1, []( int i ) { return i; } ); make_edge( f1, f2 ); make_edge( f2, f3 ); f1.try_put(1); f1.try_put(2); spin_for(0.1); t.cancel_group_execution(); g.wait_for_all();本例中f2会对输入 1 打印完整的 Begin/End但不会再接收输入 2——因为取消发生在输入 1 的任务启动之后、输入 2 的任务启动之前。方式二节点内部自取消在节点 body 内部通过task::self().group()获取当前任务的task_group_context并取消graph g; function_node int, int f1( g, 1, []( int i ) { return i; } ); function_node int, int f2( g, 1, []( const int i ) - int { cout Begin i \n; spin_for(0.2); cout End i \n; task::self().group()-cancel_group_execution(); return i; } ); function_node int, int f3( g, 1, []( int i ) { return i; } ); make_edge( f1, f2 ); make_edge( f2, f3 ); f1.try_put(1); f1.try_put(2); g.wait_for_all();要点即使构造图时没有显式传入task_group_context也可以从节点 body 中取回它——因为每个图内部都拥有或关联一个上下文节点运行时总能通过task::self().group()拿到。五、生命周期管理图对象不拥有节点图对象不拥有does not own与其关联的节点这是 oneTBB 生命周期规则中最重要的约束必须确保图对象的生命周期长于图中所有节点以及与之关联的任何活动的生命周期。换句话说销毁顺序必须满足先销毁节点后销毁图。即便使用了智能指针也要显式注意节点与图的销毁顺序防止节点先于图被删除见 Graph_Object。配套的黄金法则在销毁图对象之前调用wait_for_all确保所有活动任务已完成。这一规则同样适用于图运行在后台线程的场景。官方指南 destroy_graphs_outside_main_thread 建议若不想阻塞主线程可以入队一个任务去创建图、执行并等待完成class background_task { public: void operator()() { graph g; function_node int, int f( g, 1, []( int i ) - int { return spin_for(i); } ); f.try_put(1); g.wait_for_all(); } }; void no_wait_for_all_enqueue() { task_arena a; a.enqueue(background_task()); // do other things without waiting… }需要注意的是入队任务何时执行并不确定如果需要使用其结果或确保其在程序结束前完成就必须通过某种机制如信号量、future 等从入队任务中发出图已完成的通知。六、把图对象用起来一个带节点与边的最小数据流图图对象的真实价值体现在与节点Nodes、边Edges配合使用时。以下代码综合了 Nodes 与 Edges 两篇指南的内容构建了一个完整可运行的最小图graph g; // nunlimited 并发三个消息的处理任务可并行 function_node int, int n( g, oneapi::tbb::flow::unlimited, []( int v ) - int { cout v; spin_for( v ); cout v; return v; } ); // m并发上限 1所有消息串行处理 function_node int, int m( g, 1, []( int v ) - int { v * v; cout v; spin_for( v ); cout v; return v; } ); make_edge( n, m ); // 建立从 n 到 m 的有向边 n.try_put( 1 ); n.try_put( 2 ); n.try_put( 3 ); g.wait_for_all(); // 等待整图所有任务完成要点梳理function_node构造签名function_nodeInput, Output(graph g, size_t concurrency, Body body)。其中concurrency控制节点 body 允许并发执行的调用数1表示串行unlimited表示只要有消息到达就派生任务也可以指定4、8等具体数值限制并发上限make_edge(p, s)p为前驱节点predecessors为后继节点successor消息沿有向边自动传递try_put不阻塞若节点因并发限制无法立即派生任务消息会被缓冲在节点内部Flow_Graph_Buffering_in_Nodes待并发限制允许时再依次处理任务 ≠ 线程派生多个任务并不等于创建多个线程实际并行度受 oneTBB 线程池中可用线程数约束。关于wait_for_all还有一个值得注意的底层行为见 Mapping_Nodes2Tasks调用wait_for_all的线程并不会空转等待而是会参与执行 oneTBB 工作池work pool中的其他任务这是 oneTBB 高吞吐的关键设计之一。七、总结图对象使用清单创建graph g;——图对象不可拷贝生命周期覆盖其所有节点等待销毁前、读结果前调用g.wait_for_all()这是最常被遗漏的调用复用一轮计算结束后可调用g.reset()重置整图节点状态开启新一轮取消外部通过task_group_context::cancel_group_execution()或节点内部通过task::self().group()-cancel_group_execution()销毁顺序先节点后图即便使用智能指针也要显式保证该顺序后台运行用task_arena::enqueue将建图 执行 wait_for_all打包入队避免阻塞主线程。图对象是 oneTBB Flow Graph 的基石理解它集合容器 整图操作入口的双重角色并严格遵守先 wait_for_all 再销毁的生命周期规则就能避开绝大多数数据流编程中的崩溃与神秘行为。相关实现的底层源码可在 third-party/tbb/include/oneapi/tbb/detail/_flow_graph_impl.h 中继续深入研读。【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号