您好,欢迎来到聚文网。 登录 免费注册
深入理解并行编程

深入理解并行编程

全球*尖黑客编著,众多业界大咖推荐,20年传奇工匠程序员翻译!
  • 字数: 860
  • 装帧: 简装
  • 出版社: 电子工业出版社
  • 作者: (美)Paul E.Mckenney (保罗·E·麦肯尼) 著 谢宝友 译
  • 出版日期: 2017-07-01
  • 商品条码: 9787121315084
  • 版次: 1
  • 开本: 其他
  • 页数: 524
  • 出版年份: 2017
定价:¥129 销售价:登录后查看价格  ¥{{selectedSku?.salePrice}} 
库存: {{selectedSku?.stock}} 库存充足
{{item.title}}:
{{its.name}}
精选
编辑推荐
关注性能的底层、应用层开发者人手推荐的案头手册!
内容简介
本书首先以霍金提出的两个理论物理限制为引子,解释了多核并行计算兴起的原因,并从硬件的角度阐述并行编程的难题。接着,本书以常见的计数器为例,探讨其不同的实现方法及适用场景。在这些实现方法中,除了介绍常见的锁以外,本书还重点介绍了RCU的使用及其原理,以及实现RCU的基础:内存屏障。很后,本书还介绍了并行软件的验证,以及并行实时计算等内容。本书适合于对并行编程有兴趣的大学生、研究生,以及需要对项目进行深度性能优化的软硬件工程师,特别值得一提的是,本书对操作系统内核工程师也很有价值。
作者简介
保罗·E·麦肯尼,从事编程工作已经近40年,其中,超过一半以上的时间花费在并行硬件上,这些工作使他在一部分人群中赢得了“特立独行者”的名声。Paul于2002年当选
为IBM技术学院成员,在过去的10年中,Paul一直是IBM LiUX技术中心的杰出工程师。Paul也维护Linux内核中的RCLJ实现,RCU支持高性能、可扩展、实时响应和节能等多种不同的任务类型。在此之前,他曾在Sequent开发DYNIX/ptx内核。更早时期,他曾从事数据无线电、互联网协议、系统管理、业务应用程序和实时系统相关工作。
他在1981年获得计算机科学学士学位和机械工程学士学位,1988年获得计算机科学硕士学位,这些学位均来自于俄勒冈州立大学。2004年在俄勒冈州健康与科学大学的计算机科学与工程系获得博士学位,并于2015年成为俄勒冈州立大学杰出工程师学院的成员。2016年,他被任命为俄勒冈州立大学的客座教授。他发表了200多篇文章,拥有100多项专利。他有超过1000个补丁被纳入Linux内核,曾受邀参加了10届Linux内核峰会和8次Linux Real-Time峰会。曾担任6届Linux Plumbers大会程序委员会。自2007年以来,他一直在C++标准委员会任职,主要关注领域是并发。
他在SRIInternational的公司田径队主攻长跑,在此期间,该队在“美国国家企业杯赛”中拿过4次优选,1次亚军。他曾在美国多地参加长跑比赛。很近,年纪渐长的他开始专注于徒步和健身锻炼。
目录
目 录 章 如何使用本书 1 1.1 路线图 1 1.2 小问题 2 1.3  除本书之外的选择 3 1.4 示例源代码 4 1.5 这本书属于谁 4 第2章 简介 6 2.1 导致并行编程困难的历史原因 6 2.2 并行编程的目标 7 2.2.1 性能 8 2.2.2 生产率 9 2.2.3 通用性 9 2.3 并行编程的替代方案 11 2.3.1 串行应用的多个实例 11 2.3.2 使用现有的并行软件 11 2.3.3 性能优化 12 2.4 是什么使并行编程变得复杂 12 2.4.1 分割任务 13 2.4.2 并行访问控制 13 2.4.3 资源分割和复制 14 2.4.4 与硬件的交互 14 2.4.5 组合使用 14 2.4.6 语言和环境如何支持这些任务 14 2.5 本章的讨论 15 第3章 硬件和它的习惯 16 3.1 概述 16 3.1.1 流水线CPU 16 3.1.2 内存引用 17 3.1.3 原子操作 18 3.1.4 内存屏障 19 3.1.5 高速缓存未命中 19 3.1.6 I/O操作 19 3.2 开销 20 3.2.1 硬件体系结构 20 3.2.2 操作的开销 21 3.3 硬件的免费午餐 23 3.3.1 3D集成 23 3.3.2 新材料和新工艺 24 3.3.3 是光,不是电子 24 3.3.4 专用加速器 24 3.3.5 现有的并行软件 25 3.4 对软件设计的启示 25 第4章 办事的家伙 27 4.1 脚本语言 27 4.2 POSIX多进程 28 4.2.1 POSIX进程创建和销毁 28 4.2.2 POSIX线程创建和销毁 30 4.2.3 POSIX锁 31 4.2.4 POSIX读/写锁 34 4.3 原子操作 37 4.4 Linux内核中类似POSIX的操作 38 4.5 如何选择趁手的工具 39 第5章 计数 40 5.1 为什么并发计数不可小看 41 5.2 统计计数器 42 5.2.1 设计 43 5.2.2 基于数组的实现 43 5.2.3 最终结果一致的实现 44 5.2.4 基于每线程变量的实现 46 5.2.5 本节讨论 48 5.3 近似上限计数器 48 5.3.1 设计 48 5.3.2 简单的上限计数实现 50 5.3.3 关于简单上限计数的讨论 55 5.3.4 近似上限计数器的实现 55 5.3.5 关于近似上限计数器的讨论 55 5.4 精确上限计数 56 5.4.1 原子上限计数的实现 56 5.4.2 关于原子上限计数的讨论 62 5.4.3 Signal-Theft上限计数的设计 62 5.4.4 Signal-Theft上限计数的实现 63 5.4.5 关于Signal-Theft上限计数的讨论 68 5.5 特殊场合的并行计数 68 5.6 关于并行计数的讨论 69 5.6.1 并行计数的性能 70 5.6.2 并行计数的专门化 71 5.6.3 从并行计数中学到什么 71 第6章 对分割和同步的设计 73 6.1 分割练习 73 6.1.1 哲学家就餐问题 73 6.1.2 双端队列 75 6.1.3 关于分割问题示例的讨论 81 6.2 设计准则 82 6.3 同步粒度 83 6.3.1 串行程序 84 6.3.2 代码锁 85 6.3.3 数据锁 86 6.3.4 数据所有权 88 6.3.5 锁粒度与性能 88 6.4 并行快速路径 90 6.4.1 读/写锁 91 6.4.2 层次锁 91 6.4.3 资源分配器缓存 92 6.5 分割之外 97 6.5.1 使用工作队列的迷宫问题并行解法 97 6.5.2 另一种迷宫问题的并行解法 100 6.5.3 性能比较I 102 6.5.4 另一种迷宫问题的串行解法 104 6.5.5 性能比较II 104 6.5.6 未来展望与本节总结 105 6.6 分割、并行化与优化 106 第7章 锁 107 7.1 努力活着 108 7.1.1 死锁 108 7.1.2 活锁与饥饿 114 7.1.3 不公平的锁 116 7.1.4 低效率的锁 117 7.2 锁的类型 117 7.2.1 互斥锁 117 7.2.2 读/写锁 118 7.2.3 读/写锁之外 118 7.2.4 范围锁 119 7.3 锁在实现中的问题 121 7.3.1 基于原子交换的互斥锁实现示例 121 7.3.2 互斥锁的其他实现 122 7.4 基于锁的存在保证 124 7.5 锁:是英雄还是恶棍 125 7.5.1 应用程序中的锁:英雄 125 7.5.2 并行库中的锁:只是一个工具 126 7.5.3 并行化串行库时的锁:恶棍 128 7.6 总结 130 第8章 数据所有权 131 8.1 多进程 131 8.2 部分数据所有权和pthread线程库 132 8.3 函数输送 132 8.4 指派线程 132 8.5 私有化 133 8.6 数据所有权的其他用途 133 第9章 延后处理 134 9.1 引用计数 134 9.1.1 各种引用计数的实现 135 9.1.2 危险指针 140 9.1.3 支持引用计数的Linux原语 141 9.1.4 计数优化 142 9.2 顺序锁 142 9.3 读-复制-修改(RCU) 145 9.3.1 RCU介绍 145 9.3.2 RCU基础 147 9.3.3 RCU用法 155 9.3.4 Linux内核中的RCU API 166 9.3.5 “玩具式”的RCU实现 171 9.3.6 RCU练习 188 9.4 如何选择 188 9.5 更新端怎么办 190 0章 数据结构 191 10.1 从例子入手 191 10.2 可分割的数据结构 192 10.2.1 哈希表的设计 192 10.2.2 哈希表的实现 192 10.2.3 哈希表的性能 195 10.3 读侧重的数据结构 197 10.3.1 受RCU保护的哈希表的实现 197 10.3.2 受RCU保护的哈希表的性能 199 10.3.3 对受RCU保护的哈希表的讨论 201 10.4 不可分割的数据结构 201 10.4.1 可扩展哈希表的设计 202 10.4.2 可扩展哈希表的实现 203 10.4.3 可扩展哈希表的讨论 210 10.4.4 其他可扩展的哈希表 211 10.5 其他数据结构 214 10.6 微优化 214 10.6.1 实例化 215 10.6.2 比特与字节 215 10.6.3 硬件层面的考虑 216 10.7 总结 217 1章 验证 218 11.1 简介 218 11.1.1 BUG来自于何处 218 11.1.2 所需的心态 220 11.1.3 应该何时开始验证 221 11.1.4 开源之路 221 11.2 跟踪 222 11.3 断言 223 11.4 静态分析 224 11.5 代码走查 224 11.5.1 审查 224 11.5.2 走查 225 11.5.3 自查 225 11.6 几率及海森堡BUG 227 11.6.1 离散测试统计 228 11.6.2 滥用离散测试统计 229 11.6.3 持续测试统计 229 11.6.4 定位海森堡BUG 232 11.7 性能评估 235 11.7.1 性能基准 236 11.7.2 剖析 236 11.7.3 差分分析 237 11.7.4 微基准 237 11.7.5 隔离 237 11.7.6 检测干扰 238 11.8 总结 242 2章 形式验证 244 12.1 通用目的的状态空间搜索 244 12.1.1 Promela和Spin 244 12.1.2 如何使用 Promela 249 12.1.3 Promela 示例: 锁 251 12.1.4 Promela 示例: QRCU 254 12.1.5 Promela初试牛刀:dynticks和可抢占RCU 260 12.1.6 验证可抢占RCU和dynticks 264 12.2 特定目的的状态空间搜索 288 12.2.1 解析Litmus测试 289 12.2.2 Litmus测试意味着什么 290 12.2.3 运行Litmus测试 291 12.2.4 PPCMEM讨论 292 12.3 公理方法 293 12.4 SAT求解器 294 12.5 总结 295 3章 综合应用 296 13.1 计数难题 296 13.1.1 对更新进行计数 296 13.1.2 对查找进行计数 296 13.2 使用RCU拯救并行软件性能 297 13.2.1 RCU和基于每CPU变量的统计计数 297 13.2.2 RCU及可插拔I/O设备的计数器 300 13.2.3 数组及长度 300 13.2.4 相关联的字段 301 13.3 散列难题 302 13.3.1 相关联的数据元素 302 13.3.2 更新友好的哈希表遍历 303 4章 高级同步 304 14.1 避免锁 304 14.2 内存屏障 304 14.2.1 内存序及内存屏障 305 14.2.2 如果B在A后面,并且C在B后面,为什么C不在A后面 306 14.2.3 变量可以拥有多个值 307 14.2.4 能信任什么东西 308 14.2.5 锁实现回顾 312 14.2.6 一些简单的规则 313 14.2.7 抽象内存访问模型 314 14.2.8 设备操作 315 14.2.9 保证 315 14.2.10 什么是内存屏障 316 14.2.11 锁约束 325 14.2.12 内存屏障示例 326 14.2.13 CPU缓存的影响 328 14.2.14 哪里需要内存屏障 329 14.3 非阻塞同步 329 14.3.1 简单NBS 330 14.3.2 NBS讨论 331 5章 并行实时计算 332 15.1 什么是实时计算 332 15.1.1 软实时 332 15.1.2 硬实时 333 15.1.3 现实世界的实时 334 15.2 谁需要实时计算 336 15.3 谁需要并行实时计算 337 15.4 实现并行实时系统 337 15.4.1 实现并行实时操作系统 339 15.4.2 实现并行实时应用 349 15.5 实时VS.快速:如何选择 351 6章 易于使用 353 16.1 简单是什么 353 16.2 API设计的Rusty准则 353 16.3 修整Mandelbrot集合 354 7章 未来的冲突 357 17.1 曾经的CPU技术不代表未来 357 17.1.1 单处理器Uber Alles 358 17.1.2 多线程Mania 359 17.1.3 更多类似的场景 359 17.1.4 撞上内存墙 359 17.2 事务内存 360 17.2.1 外部世界 361 17.2.2 进程修改 364 17.2.3 同步 367 17.2.4 讨论 370 17.3 硬件事务内存 371 17.3.1 HTM与锁相比的优势 372 17.3.2 HTM与锁相比的劣势 373 17.3.3 HTM与增强后的锁机制相比的劣势 379 17.3.4 HTM最适合的场合 380 17.3.5 潜在的搅局者 380 17.3.6 结论 382 17.4 并行函数式编程 383 附录A 重要问题 385 A.1 “After”的含义是什么 385 A.2 “并发”和“并行”之间的差异是什么 388 A.3 现在是什么时间 389 附录B 同步原语 391 B.1 组织和初始化 391 B.1.1 smp_init() 391 B.2 线程创建、销毁及控制 392 B.2.1 create_thread() 392 B.2.2 smp_thread_id() 392 B.2.3 for_each_thread() 392 B.2.4 for_each_running_thread() 392 B.2.5 wait_thread() 393 B.2.6 wait_all_threads() 393 B.2.7 用法示例 393 B.3 锁 394 B.3.1 spin_lock_init() 394 B.3.2 spin_lock() 394 B.3.3 spin_trylock() 394 B.3.4 spin_unlock() 394 B.3.5 用法示例 395 B.4 每线程变量 395 B.4.1 DEFINE_PER_THREAD() 395 B.4.2 DECLARE_PER_THREAD() 395 B.4.3 per_thread() 395 B.4.4 __get_thread_var() 396 B.4.5 init_per_thread() 396 B.4.6 用法示例 396 B.5 性能 396 附录C 为什么需要内存屏障 397 C.1 缓存结构 397 C.2 缓存一致性协议 399 C.2.1 MESI状态 399 C.2.2 MESI协议消息 400 C.2.3 MESI状态图 400 C.2.4 MESI协议示例 401 C.3 存储导致不必要的停顿 402 C.3.1 存储缓冲 403 C.3.2 存储转发 403 C.3.3 存储缓冲区及内存屏障 404 C.4 存储序列导致不必要的停顿 406 C.4.1 使无效队列 406 C.4.2 使无效队列及使无效应答 407 C.4.3 使无效队列及内存屏障 407 C.5 读和写内存屏障 409 C.6 内存屏障示例 410 C.6.1 乱序体系结构 410 C.6.2 示例1 411 C.6.3 示例2 412 C.6.4 示例3 412 C.7 特定的内存屏障指令 413 C.7.1 Alpha 414 C.7.2 AMD64 417 C.7.3 ARMv7-A/R 417 C.7.4 IA64 418 C.7.5 PA-RISC 418 C.7.6 POWER / Power PC 418 C.7.7 SPARC RMO、PSO及TSO 419 C.7.8 x86 420 C.7.9 zSeries 421 C.8 内存屏障是永恒的吗 421 C.9 对硬件设计者的建议 422 附录D 小问题答案 423 D.1 如何使用本书 423 D.2 简介 424 D.3 硬件和它的习惯 427 D.4 办事的家伙 429 D.5 计数 433 D.6 对分割和同步的设计 445 D.7 锁 449 D.8 数据所有权 455 D.9 延迟处理 456 D.10 数据结构 471 D.11 验证 473 D.12 形式验证 478 D.13 综合应用 481 D.14 高级同步 483 D.15 并行实时计算 486 D.16 易于使用 487 D.17 未来的冲突 487 D.18 重要问题 490 D.19 同步原语 491 D.20 为什么需要内存屏障 491 附录E 术语 495 附录F 感谢 502 F.1 评审者 502 F.2 硬件提供者 502 F.3 原始出处 503 F.4 图表作者 503 F.5 其他帮助 505
摘要
作者序我希望能够说本书的诞生源于甜蜜和光明,但这无疑是个谎言。和许多需要长年坚持努力的事情一样,本书经过了大量挫折才得以诞生。你看,大约10年前,在并发领域的一个行业专家小组研讨会上,我很荣幸得以提问最后一个问题。一些参会的专家长篇大论地讨论了并行编程的高难度,所以我问为什么并行编程不会在10或20年内成为司空见惯的事情。大多数小组成员一点都不喜欢这个问题。事实上,第一个小组成员试图用一个简短的回答敷衍了事,但我很容易地做了简短的反驳。无奈,他尝试给出了第二个简短回答,我也继续反驳。几轮之后,他大声喊叫:“像你这样的人应该用锤子敲敲头!”我不甘示弱地回答道:“那你可要排队才能敲得到。”我不认为这种交流是特别有启发性的,相反这展示了一个毫无疑问的事实:这位“业内”专家对于并行编程一无所知。不过在场的其他听众却认为这场对话非常有启发性,尤其是那一位感谢我提出这个问题的听众,他的眼里甚至含着泪水。他像学徒一样在Sequent 计算机系统公司学到了并行编程的诀窍,正如我曾经所做的那样。后来他跳槽去了另一家公司,他的新雇主开始涉足并行编程。出乎他意料之外,事情发展得并非一帆风顺。正如他所说,“我已经足足跟他们说了两年,只要你用正确的办法,这并不是很难,但他们完全不听我的话!”现在,我们很容易将这个悲伤故事里面的团队作为反面教材。但是在他们的看法中,并行编程等于用你自己的智力伤害自己。除非你了解实现并行性的正确方法,否则在意识到遇到麻烦之前,你越聪明,挖的坑就越深。因此,你越聪明,并行编程看起来就越难。不仅如此,在这件事发生时,极少有人知道如何进行并行编程,这意味着大多数人刚刚开始了解到他们为自己挖的并行编程坑的深度。即使如此,当这个人用哽咽的声音讲述他的故事,眼泪滑过他的脸庞时,我意识到我不得不做一些事。那就是写眼前这本书,这里面不仅仅浓缩我自己四分之一个世纪的经历,还有其他人加起来数不清几个世纪的经历。我的母语是英语,英语是我唯一可以声称掌握了的语言。但幸运的是,感谢鲁阳和谢宝友所付出的巨大努力,现在中文版翻译即将面世。我希望这本书不仅可以帮助你学习我所知道的知识,从而不再需要担心并行编程,还能使你能够创建属于自己的并行编程新发现!Paul E. McKenney推荐序读着《深入理解并行编程》的样章,我的脑海里不断地浮现出9年前的一幕幕。我在网上寻找操作系统的志同道合者,看到一个税收专业中专毕业者的自荐信,其时他已具有10年的IT行业工作经验,从事过大量手机、通信行业软件研发工作,担任过项目总监研发管理工作,在电信应用开发方面已经做得比较成功。但他对操作系统有浓厚的兴趣、执着的追求,放弃了在高层应用软件方面的既有优势,专注于操作系统的研究。离职在家,利用半年时间开发出一个嵌入式操作系统模型,计划两年内研发一款自研操作系统。有感于他的执着和热爱,我向公司争取破格录取他。我认为做一个操作系统不难,但做生态难,做商业成功难,建议他深入学习开源Linux的技术,站到巨人肩膀上,再结合操作系统团队的商业模式探索,争取把操作系统做成功。于是,他如痴如醉地研究Linux内核,在一年时间里,每天晚上坚持花三个小时以上的时间钻研《深入理解Linux内核》这本书,还将自己的读书心得笔记共享到团队论坛上,并对开源内核进行注解,分享到开源论坛上。2008年正是多核架构快速发展之时,操作系统的支持参差不齐,驱动、应用开发模式不成熟,既有单态单核单进程的业务应用如何进行重构和演进,方案设计、开发联调、故障排查、系统调优又会遇到很多复杂和棘手的问题,中兴通讯操作系统团队需要支撑公司所有产品、各种CPU架构、各种复杂业务场景,团队面临着前所未有的技术和进度压力。团队成员除了在研发一线通过不断实践进行被动积累和提升外,也加强了主动的理论知识提升,阅读《深入理解并行编程》就是其中之一。令我印象非常深刻的是,多核故障往往比较随机和复杂,难以复现和理解,但以谢宝友为代表的团队成员往往可以通过阅读业务、驱动、内核代码就定位到故障根源,整理出故障逻辑,我认为这与他们的系统理论水平提升是分不开的。非常欣慰的是,我们成功地解决了这个过渡时期涌现的诸如多核内存序相关故障,利用无锁并行编程优化了系统性能。时至今日,我们团队已经从30人发展到数百人,嵌入式操作系统已全面应用于公司所有产品,在全球稳定商用,并且扩展应用到电力、铁路、汽车等领域,2016年获得了第四届中国工业大奖。另一方面,站在技术的角度来看,在计算机领域,并行编程的困难是众所周知的。有4、5年编程经验的读者,可能或多或少遇到过并行编程的问题,最著名的问题可能就是死锁。读者需要掌握调试死锁问题的技巧,以及避免死锁问题的编程技术。喜欢深入思考的读者,在理解并解决死锁问题之后,可能还会阅读并行编程方面的书籍,进一步接触到活锁、饥饿等更有趣的并行编程问题。中兴通讯操作系统团队的同事,就曾经在开源虚拟化软件中遇到过类似的问题:虚拟机容器在互斥锁的保护下,轮询系统状态并等待状态变化。这样的轮询操作造成了进程调度不及时,系统状态迟迟不能变化。这是一个典型的活锁问题。在多核系统越来越普及的今天,类似的活锁问题更容易出现。解决这类问题,需要经验丰富的工程师,借助多种调试工具,花费不少的时间。但是,并行编程仅仅与锁相关吗?在摩尔定律尚未失效时,并行编程确实主要与锁紧密相关。但是,我们看看霍金向IT工程师所提出的两个难题:1.有限的光速;2.物质的原子特性。这两个难题最终会将CPU频率的理论上限限制在10GHz以内,不可避免地使摩尔定律失效。要继续提升硬件性能,需要借助于多核扩展。要充分发挥多核系统的性能,必须提升并行软件的扩展性。也就是说,并行软件需要尽量减少锁冲突,避免由于锁竞争而引起性能急剧下降。这不是一件简单的事情!我们知道,Linux操作系统在接近20年的时候内,一直受到大内核锁的困扰。为了彻底抛弃大内核锁,开源社区近几年内做出了艰辛的努力,才实现了这个目标。即使如此,Linux内核仍然大量使用不同种类的锁,并且不可能完全放弃锁的使用。也许你会说,在多核系统中,有一种简单的避免锁的方法,就是原子变量。在某些架构中,原子变量是由单条指令实现的,性能“想必”不差,使用方法也简单。曾经有一位具有十多年编程经验的工程师也表达过类似的观点。在此,有两个问题需要回答。1.这样的原子操作指令,其性能真的不差?它的执行周期是否可能达到上千个时钟周期?2.对于多个相互之间有逻辑关联的变量,原子操作是否满足要求?实际上,多核系统中的并行软件,除了常见的锁之外,还需要使用冒险指针、RCU、内存屏障这样的重量级并行编程工具。这些编程工具都属于“无锁编程”的范畴。即使在Linux内核开源社区工作10年以上的资深工程师,也不一定能真正灵活自如地使用RCU、内存屏障来进行并行编程。因此,真正了解并行编程的读者,难免在面对并行编程难题时,有一种“抚襟长叹息”的感觉。然而,我们知道,有很多重要的应用依赖于并行——图形渲染、密码破解、图像扫描、物理与生物过程模拟等。有一个极端的例子,在证券交易所,为了避免长距离传输引起的通信延迟(理论上,光束绕地球一周需要大概130ms),需要将分析证券交易的计算机放到更接近证券交易的地方,并且压榨出计算机的所有性能。这样,才能保证达成有利的证券交易。可以毫不夸张地说,对软件性能有苛刻需求的软件工程师和大型软件开发企业,都需要真正掌握并行编程的艺术,特别是“无锁编程”的艺术。一旦真正掌握了,它就会为你带来意想不到的性能提升。曾经有一位著名企业的高级专家,在应用了本书所述的RCU后,软件性能提升了大约10倍。本书正是这样一本深入讲解多核并行编程,特别是无锁编程的好书。首先,本书作者Paul具有40年软件编程职业生涯,他大部分的工作都与并行编程相关。即使在领导IBM Linux中心时,他仍然坚持每天编程,是一名真正的“工匠”。同时,作者也是Linux开源社区RCU模块的领导者和维护者。认真阅读本书后,不得不钦佩于作者在并行编程方面的真知灼见和实践能力。例如作者亲自编写了一个软件用例,来考察CPU核之间原子操作和锁的性能,得出一个结论,原子操作和锁可能消耗超过1000个CPU时钟周期;作者也编写过另外一个关于全局变量的用例,其中一个CPU核递增操作一个全局变量,同时在不同的CPU核上观察所读到的全局变量值。这个用例向读者展示了多核系统令人惊奇的、反直觉的效果;作者对内存屏障的讲解,特别是内存屏障传递性的讲解,十分深入。这些深入的内容,难得一见,非大师不能为。其次,这本书也得到Linux内核社区和应用软件专家的一致推荐。这些推荐者既包括Linux社区大名鼎鼎的Ingo Molnar、Rusty Russel、Greg Kroah-Hartman、Maged M.Micheal,也包括国内活跃于社区的庞训磊、Shawn Guo等开源贡献者,还包括Linaro开源组织的领导和资深工程师,以及在BAT工作多年的高级应用软件专家。第三,这本书的内容比较全面。除了介绍常见的锁以外,还重点介绍了RCU的使用及其原理,以及实现RCU的基础:内存屏障。本书最后还介绍了并行软件的验证,以及并行实时计算等内容。实际上,其中每一部分都是并行编程的宝藏。由于篇幅和难度的原因,作者在当前版本中,将RCU部分作了大幅压缩。对RCU感兴趣的读者可以阅读早期原版著作。即使如此,本书对RCU的讲解也非常深入。对于并行软件的验证,作者提出了不少独特的观点,这些观点和作者多年的编程经验息息相关,与常见的理论著作相比,有一定的新意。形式验证部分,作者以实际的例子,一步一步讲述验证过程,很明显,作者亲自动手做过这种验证。并行实时计算部分,是作者新增的内容,别具一格,值得读者细读。内存屏障部分,是本书一个难点,借助于作者在这方面的功力

蜀ICP备2024047804号

Copyright 版权所有 © jvwen.com 聚文网