尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
build2 源码剖析:DAG 构建模型与调度器并行构建原理
build2 源码剖析DAG 构建模型与调度器并行构建原理【免费下载链接】build2build2 build system项目地址: https://gitcode.com/gh_mirrors/bu/build2build2 是一款现代化的开源 C/C 构建系统其最吸引人的特性之一就是基于DAG 构建模型有向无环图与调度器并行构建的设计。本文将从源码层面剖析 build2 如何用一张依赖图描述整个工程并通过自研调度器让多个编译任务真正并行执行帮助读者理解并行构建原理也为想深入阅读 build2 源码的开发者提供一份地图。为什么说 build2 的并行构建不简单很多构建系统如早期的 make是串行执行的编译完 A 再编译 B。而 build2 在设计的起点就把并行调度写进了核心libbuild2/scheduler.hxx中明确写道调度器最适合执行重量级任务例如运行一个编译进程因为在这种情况下线程同步的开销相对于任务本身可以忽略不计。这意味着 build2 的并行不是简单开几个线程而是一套完整的任务调度体系。DAG 构建模型一切从依赖图开始在 build2 的世界里整个构建过程可以被抽象成一张有向无环图DAG节点target每一个需要被构建的对象比如hello.o、hello可执行文件边prerequisite目标之间的依赖关系比如hello.o依赖hello.cxxhello依赖hello.o。因为这张图是无环的所以 build2 才能安全地并发调度只有当一个节点的所有前置依赖都构建完成后它才能开始构建。这张图的数据结构定义在libbuild2/target.hxx而图的构建与遍历逻辑集中在libbuild2/algorithm.cxx中。目标状态机并行安全的生命周期为了让多个线程同时操作一张依赖图而不出错build2 为每个目标定义了一套状态机见libbuild2/target-state.hxx状态含义unknown尚未处理unchanged已检查无需重新构建增量构建的成果postponed被推迟如最后一个执行模式下的中间目标busy正在被某个线程构建中changed构建完成且内容发生了变化failed构建失败group状态继承自其所属的目标组这套状态机是并行构建的基石多个线程看到同一个目标时通过原子操作竞争busy状态从而保证同一个目标永远不会被两个线程同时构建。匹配与执行构建的两个关键阶段在libbuild2/algorithm.cxx中build2 把构建拆成两个阶段匹配阶段match为目标找到合适的规则rule并确定它是否需要重新构建。对应源码中的match_impl()函数它通过lock_impl()获取目标锁然后依次经历tried → touched → matched → applied等内部偏移状态执行阶段execute真正运行编译命令或配方recipe对应execute_impl()函数。有趣的是这两个阶段本身也是可以并行的——匹配可以按依赖顺序并发进行执行同样如此。这为调度器提供了大量可并发的任务。调度器master 线程与 helper 线程的协作build2 的并行核心是libbuild2/scheduler.hxx中定义的scheduler类它的设计思路非常优雅master 线程负责发起并行任务。比如要更新一个目标的所有前置依赖时master 会通过async()把每个前置依赖的构建外包出去helper 线程调度器维护的一批工作线程专门执行 master 交给它们的任务。关键机制是调度器保证任意时刻处于活跃状态的线程数量不超过硬件线程数。当 master 调用wait()等待任务完成时它会被挂起suspended腾出的名额让其他线程得以激活任务完成后的 helper 线程也可能被挂起转而去唤醒一个等待中的 master。一个容易忽略的细节是挂起的线程不会被复用为 helper而是总是新建 helper 线程。源码注释解释得很清楚——这是为了让就绪的 master能尽快继续运行避免它被嵌套的wait()阻塞在调用栈深处。所以调度器实际创建的线程数通常会超过最大活跃线程数。async 与 wait并行构建的原语并行调度的两个核心原语定义在scheduler.hxx中async(start_count, task_count, ...)把任务提交到调度器。如果 helper 线程可用任务被异步执行并返回true否则任务会在wait()中同步执行甚至直接在async()调用内同步执行wait(start_count, task_count, work_queue)等待任务计数降到起始值以下。这里task_count是一个std::atomicsize_t原子计数它是线程间同步的关键。wait()还有一个work_queue参数控制等待期间是否顺便处理自己队列里的任务work_none完全不处理、work_one每做完一个任务就检查一次、work_all先清空队列再检查。这种等待时不闲着的设计让线程在阻塞期间也能贡献算力是提升并行效率的重要技巧。在algorithm.cxx的执行逻辑中我们可以清楚地看到这种用法目标从applied状态原子地切换到busy状态通过compare_exchange_strong实现然后调用ctx.sched-async(...)把execute_impl()交给调度器去并行执行最后通过fetch_sub递减任务计数并调用sched-resume()唤醒等待者。依赖计数与最后一个执行模式libbuild2/context.hxx中维护了两个重要的全局计数dependency_count尚未满足的依赖关系数量target_count尚未执行的目标数量。它们配合execution_mode执行模式一起工作。比如last模式下一个目标只有当它是最后一个被依赖者时才真正执行——这在清理clean操作中非常有用多个成员依赖同一个组时组只需被清理一次。execute_impl()中--td ! 0时直接返回postponed状态的逻辑正是这种模式的实现。死锁检测并行构建的安全网并行调度最大的风险是死锁。build2 的调度器内置了一套基于进度监测的死锁检测机制如果活跃线程长时间没有取得进展即没有完成任务调度器就会触发诊断。源码中大量出现的deactivate()/activate()调用是线程在等待外部事件如文件系统操作时主动让位给其他线程的手段同时也会暂停死锁检测的计时——因为等待外部事件的时间不算卡死。从哪几行代码开始读如果你想深入这套 DAG 构建模型与并行构建原理建议按下面的顺序阅读源码libbuild2/target-state.hxx目标状态机的完整定义是理解一切的基础libbuild2/scheduler.hxx与libbuild2/scheduler.cxx调度器的接口与实现重点看async()、wait()、deactivate()/activate()libbuild2/algorithm.cxxmatch_impl()与execute_impl()看依赖图如何被并发遍历libbuild2/context.hxx执行模式与全局计数的定义。总结build2 的并行构建原理可以浓缩为一句话用状态机保证依赖图的并发安全用任务调度器实现线程的高效协作。DAG 构建模型让 build2 能精确地知道谁先谁后而调度器让这些可以并行的任务真正跑满 CPU。理解了这两层设计你也就理解了现代高性能构建系统的核心思想——这不仅是阅读 build2 源码的钥匙对设计任何并发系统都有启发意义。【免费下载链接】build2build2 build system项目地址: https://gitcode.com/gh_mirrors/bu/build2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

微信防撤回实测:RevokeMsgPatcher 用了一周,安装步骤和坑都记下来了

微信防撤回实测:RevokeMsgPatcher 用了一周,安装步骤和坑都记下来了

微信防撤回实测:RevokeMsgPatcher 用了一周,安装步骤和坑都记下来了 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目…

📅 2026/10/10 19:15:03
RPCS3模拟器终极上手指南:3个阶段让PC轻松跑起PS3独占游戏

RPCS3模拟器终极上手指南:3个阶段让PC轻松跑起PS3独占游戏

RPCS3模拟器终极上手指南:3个阶段让PC轻松跑起PS3独占游戏 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 客厅角落那台 PS3,上一次通电大概是五年前。想重温《最后生还者…

📅 2026/10/21 13:24:42
洛雪音乐音源库免费入门指南:三步配好全网无损音乐,一网打尽五大平台

洛雪音乐音源库免费入门指南:三步配好全网无损音乐,一网打尽五大平台

洛雪音乐音源库免费入门指南:三步配好全网无损音乐,一网打尽五大平台 【免费下载链接】lxmusic- lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/gh_mirrors/lx/lxmusic- 你是否也有过这样的经历:想听一首老歌&…

📅 2026/10/7 14:01:16
MORE NEWS

更多资讯

📰

我用DeepSeek刚开放的搜索API给Agent装了个联网大脑:成本降了92%,附完整生产级代码

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

【Use Cases】10. 使用LlamaCloud和Neo4J构建知识图谱

1. 案例目标本案例展示了如何使用LlamaCloud套件和Neo4j构建知识图谱,将非结构化的法律文档转换为结构化的知识表示。通过结合LlamaParse、LlamaClassify和LlamaExtract等工具,实现从原始文档到可查询知识图谱的完整流程。主要目标包括:使用L…

📰

众口不再难调 Astro12发布星座洗脑神曲(图)

中新网在8月2日发出报道说, 最近的时候, 万家文化那个公司旗下有拾贰星座北京娱乐传媒这个板块的公司, 他们联合了日本那边顶级的制作团队。这些团队都投入了比较重的资金来打造这个项目。这个项目是国内第一个关于星座的女团。现在这个女团已经正式发行了第一支歌曲。这支歌曲…

📰

【无需VIP】Odin V3.5 Unity插件:属性绘制器使用指南,三步搞定复杂数据编辑

【无需VIP】Odin V3.5 Unity插件:属性绘制器使用指南,三步搞定复杂数据编辑 【免费下载链接】Unity插件OdinV3.5下载 本仓库提供Unity插件——Odin V3.5的下载资源。Odin是一款强大的Unity插件,旨在提升Unity开发者的生产力,简化复…

📰

什么是三色激光显示?主流技术方案与代表产品盘点

什么是三色激光显示?(一句话定义)三色激光显示,是指分别使用红(R)、绿(G)、蓝(B)三个独立波长的激光作为发光光源,经合光后投射成像的显示技术。 …

📰

Python二手房数据采集与可视化分析毕业设计实战

简介:这份资源是面向计算机、电子信息工程、数学等专业大学生的毕业设计与课程设计参考资料,围绕Python二手房数据采集与可视化分析展开,适合作为期末大作业或毕业设计的完整方案模板。压缩包共155个文件,约35.13MB,包…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬