** 有需要该书的朋友请回帖沟通寄送方式,谢谢!**
深入理解计算机系统(原书第 2 版)
作者
- (美)Randal E.Bryant
- David O'Hallaron
Randal E.Bryant 1973 年于密歇根大学(University of Michigan)获得学士学位,随即就读于麻省理工学院的研究生院,并在 1981 年获计算机博士学位。他在加州理工学院(California Institute of Technology)做了三年助教,从 1984 年至今一直是卡内基-梅隆大学的教师。他现在是计算机科学的大学教授和计算机科学学院的院长。他同时还受邀于电子和计算机工程系。
他从事本科生和研究生计算机系统方面课程的教学超过 30 年。在讲授计算机体系结构课程多年后,他开始把关注点从如何设计计算机转移到程序员如何在更好的了解系统的情况下编写出更有效和更可靠的程序。他和 O’Hallaron 教授一起在卡内基梅隆大学开设了 15-213“计算机系统导论”课程,那便是此书的基础。他还教授一些有关算法、编程、计算机网络和 VLSI(超大规模集成电路)设计方面的课程。
Bryant 教授的主要研究内容是设计软件工具来帮助软件和硬件设计者验证其系统正确性。其中,包括几种类型的模拟器,以及用数学方法来证明设计正确性的形式化验证工具。他发表了 150 多篇技术论文。包括 Intel、FreeScale、IBM 和 Fujitsu 在内的主要计算机制造商都使用着他的研究成果。他还因他的研究获得过数项大奖。其中包括 Semiconductor Research Corporation 颁发的两个发明荣誉奖和一个技术成就奖,ACM 颁发的 Kanellakis 理论与实践奖,还有 IEEE 授予的 W.R.G.Baker 奖、Emmanuel Piore 奖和 Phil Kaufman 奖。他还是 ACM 院士、IEEE 院士和美国国家工程院院士。
David R.O’Hallaron 现为 Intel 匹兹堡实验室主任,卡内基-梅隆大学电子和计算机工程系副教授。在弗吉尼亚大学获得计算机科学的博士学位。
他教授本科生和研究生的计算机系统方面的课程,例如计算机体系结构、计算机系统导论、并行处理器设计和 Internet 服务。他和 Bryant 教授一起开设了“计算机系统导论”课程,那便是此书的基础。2004 年他获得了 CMU 计算机学院颁发的 Herbert Simon 杰出教学奖,这个奖项的获得者是基于学生的投票产生的。
O’Hallaron 教授从事计算机系统领域的研究,主要兴趣在于科学计算、数据密集型计算和虚拟化方面的软件系统。其中最著名的是 Quake 项目,一群计算机科学家、土木工程师和地震学家致力于提高对强烈地震中大地运动的预测能力。2003 年,他同 Quake 项目中其他成员一起获得了高性能计算领域中的最高国际奖项—Gordon Bell 奖。
译者
- 龚奕利
- 雷迎春
内容简介
本书从程序员的视角详细阐述计算机系统的本质概念,并展示这些概念如何实实在在地影响应用程序的正确性、性能和实用性。全书共 12 章,主要内容包括信息的表示和处理、程序的机器级表示、处理器体系结构、优化程序性能、存储器层次结构、链接、异常控制流、虚拟存储器、系统级 I/O、网络编程、并发编程等。书中提供大量的例子和练习,并给出部分答案,有助于读者加深对正文所述概念和知识的理解。
本书的最大优点是为程序员描述计算机系统的实现细节,帮助其在大脑中构造一个层次型的计算机系统,从最底层的数据在内存中的表示到流水线指令的构成,到虚拟存储器,到编译系统,到动态加载库,到最后的用户态应用。通过掌握程序是如何映射到系统上,以及程序是如何执行的,读者能够更好地理解程序的行为为什么是这样的,以及效率低下是如何造成的。
本书适合那些想要写出更快、更可靠程序的程序员阅读,也适合作为高等院校计算机及相关专业本科生、研究生的教材。
目录
出版者的话
译者序
前 言
第 1 章 计算机系统漫游 1
1.1 信息就是位 + 上下文 1
1.2 程序被其他程序翻译成不同的格式 3
1.3 了解编译系统如何工作是大有益处的 4
1.4 处理器读并解释存储在存储器中的指令 5
1.4.1 系统的硬件组成 5
1.4.2 运行 hello 程序 7
1.5 高速缓存至关重要 7
1.6 存储设备形成层次结构 9
1.7 操作系统管理硬件 10
1.7.1 进程 11
1.7.2 线程 12
1.7.3 虚拟存储器 12
1.7.4 文件 13
1.8 系统之间利用网络通信 13
1.9 重要主题 15
1.9.1 并发和并行 15
1.9.2 计算机系统中抽象的重要性 17
1.10 小结 17
参考文献说明 18
第一部分 程序结构和执行
第 2 章 信息的表示和处理 20
2.1 信息存储 22
2.1.1 十六进制表示法 22
2.1.2 字 25
2.1.3 数据大小 25
2.1.4 寻址和字节顺序 26
2.1.5 表示字符串 31
2.1.6 表示代码 31
2.1.7 布尔代数简介 32
2.1.8 C 语言中的位级运算 34
2.1.9 C 语言中的逻辑运算 36
2.1.10 C 语言中的移位运算 36
2.2 整数表示 38
2.2.1 整型数据类型 38
2.2.2 无符号数的编码 39
2.2.3 补码编码 40
2.2.4 有符号数和无符号数之间的转换 44
2.2.5 C 语言中的有符号数与无符号数 47
2.2.6 扩展一个数字的位表示 49
2.2.7 截断数字 51
2.2.8 关于有符号数与无符号数的建议 52
2.3 整数运算 54
2.3.1 无符号加法 54
2.3.2 补码加法 57
2.3.3 补码的非 59
2.3.4 无符号乘法 60
2.3.5 补码乘法 60
2.3.6 乘以常数 63
2.3.7 除以 2 的幂 64
2.3.8 关于整数运算的最后思考 67
2.4 浮点数 67
2.4.1 二进制小数 68
2.4.2 IEEE 浮点表示 70
2.4.3 数字示例 71
2.4.4 舍入 74
2.4.5 浮点运算 76
2.4.6 C 语言中的浮点数 77
2.5 小结 79
参考文献说明 80
家庭作业 80
练习题答案 90
第 3 章 程序的机器级表示 102
3.1 历史观点 103
3.2 程序编码 105
3.2.1 机器级代码 106
3.2.2 代码示例 107
3.2.3 关于格式的注解 109
3.3 数据格式 111
3.4 访问信息 112
3.4.1 操作数指示符 112
3.4.2 数据传送指令 114
3.4.3 数据传送示例 116
3.5 算术和逻辑操作 118
3.5.1 加载有效地址 118
3.5.2 一元操作和二元操作 119
3.5.3 移位操作 120
3.5.4 讨论 120
3.5.5 特殊的算术操作 122
3.6 控制 123
3.6.1 条件码 124
3.6.2 访问条件码 125
3.6.3 跳转指令及其编码 127
3.6.4 翻译条件分支 129
3.6.5 循环 132
3.6.6 条件传送指令 139
3.6.7 switch 语句 144
3.7 过程 149
3.7.1 栈帧结构 149
3.7.2 转移控制 150
3.7.3 寄存器使用惯例 151
3.7.4 过程示例 152
3.7.5 递归过程 156
3.8 数组分配和访问 158
3.8.1 基本原则 158
3.8.2 指针运算 159
3.8.3 嵌套的数组 159
3.8.4 定长数组 161
3.8.5 变长数组 163
3.9 异质的数据结构 164
3.9.1 结构 164
3.9.2 联合 167
3.9.3 数据对齐 170
3.10 综合:理解指针 172
3.11 应用:使用 GDB 调试器 174
3.12 存储器的越界引用和缓冲区溢出 175
3.13 x86-64:将 IA32 扩展到 64 位 183
3.13.1 x86-64 的历史和动因 184
3.13.2 x86-64 简介 185
3.13.3 访问信息 187
3.13.4 控制 192
3.13.5 数据结构 200
3.13.6 关于 x86-64 的总结性评论 200
3.14 浮点程序的机器级表示 201
3.15 小结 201
参考文献说明 202
家庭作业 202
练习题答案 212
第 4 章 处理器体系结构 230
4.1 Y86 指令集体系结构 231
4.1.1 程序员可见的状态 231
4.1.2 Y86 指令 232
4.1.3 指令编码 233
4.1.4 Y86 异常 237
4.1.5 Y86 程序 237
4.1.6 一些 Y86 指令的详情 241
4.2 逻辑设计和硬件控制语言 HCL242
4.2.1 逻辑门 243
4.2.2 组合电路和 HCL 布尔表达式 243
4.2.3 字级的组合电路和 HCL 整数表达式 245
4.2.4 集合关系 248
4.2.5 存储器和时钟 248
4.3 Y86 的顺序实现 250
4.3.1 将处理组织成阶段 250
4.3.2 SEQ 硬件结构 258
4.3.3 SEQ 的时序 259
4.3.4 SEQ 阶段的实现 262
4.4 流水线的通用原理 267
4.4.1 计算流水线 268
4.4.2 流水线操作的详细说明 269
4.4.3 流水线的局限性 271
4.4.4 带反馈的流水线系统 272
4.5 Y86 的流水线实现 273
4.5.1 SEQ+:重新安排计算阶段 273
4.5.2 插入流水线寄存器 276
4.5.3 对信号进行重新排列和标号 277
4.5.4 预测下一个 PC279
4.5.5 流水线冒险 280
4.5.6 用暂停来避免数据冒险 283
4.5.7 用转发来避免数据冒险 285
4.5.8 加载/使用数据冒险 288
4.5.9 异常处理 289
4.5.10 PIPE 各阶段的实现 291
4.5.11 流水线控制逻辑 297
4.5.12 性能分析 305
4.5.13 未完成的工作 306
4.6 小结 308
参考文献说明 309
家庭作业 309
练习题答案 314
第 5 章 优化程序性能 324
5.1 优化编译器的能力和局限性 325
5.2 表示程序性能 328
5.3 程序示例 330
5.4 消除循环的低效率 332
5.5 减少过程调用 336
5.6 消除不必要的存储器引用 336
5.7 理解现代处理器 340
5.7.1 整体操作 340
5.7.2 功能单元的性能 343
5.7.3 处理器操作的抽象模型 344
5.8 循环展开 348
5.9 提高并行性 351
5.9.1 多个累积变量 351
5.9.2 重新结合变换 354
5.10 优化合并代码的结果小结 358
5.11 一些限制因素 359
5.11.1 寄存器溢出 359
5.11.2 分支预测和预测错误处罚 360
5.12 理解存储器性能 363
5.12.1 加载的性能 363
5.12.2 存储的性能 364
5.13 应用:性能提高技术 369
5.14 确认和消除性能瓶颈 369
5.14.1 程序剖析 370
5.14.2 使用剖析程序来指导优化 371
5.14.3 Amdahl 定律 374
5.15 小结 375
参考文献说明 375
家庭作业 376
练习题答案 378
第 6 章 存储器层次结构 382
6.1 存储技术 382
6.1.1 随机访问存储器 383
6.1.2 磁盘存储 389
6.1.3 固态硬盘 398
6.1.4 存储技术趋势 399
6.2 局部性 401
6.2.1 对程序数据引用的局部性 402
6.2.2 取指令的局部性 403
6.2.3 局部性小结 403
6.3 存储器层次结构 405
6.3.1 存储器层次结构中的缓存 406
6.3.2 存储器层次结构概念小结 408
6.4 高速缓存存储器 408
6.4.1 通用的高速缓存存储器结构 409
6.4.2 直接映射高速缓存 410
6.4.3 组相联高速缓存 416
6.4.4 全相联高速缓存 418
6.4.5 有关写的问题 420
6.4.6 一个真实的高速缓存层次结构的解剖 421
6.4.7 高速缓存参数的性能影响 422
6.5 编写高速缓存友好的代码 423
6.6 综合:高速缓存对程序性能的影响 426
6.6.1 存储器山 426
6.6.2 重新排列循环以提高空间局部性 430
6.6.3 在程序中利用局部性 433
6.7 小结 433
参考文献说明 434
家庭作业 434
练习题答案 442
第二部分 在系统上运行程序
第 7 章 链接 448
7.1 编译器驱动程序 449
7.2 静态链接 450
7.3 目标文件 450
7.4 可重定位目标文件 451
7.5 符号和符号表 452
7.6 符号解析 454
7.6.1 链接器如何解析多重定义的全局符号 455
7.6.2 与静态库链接 457
7.6.3 链接器如何使用静态库来解析引用 460
7.7 重定位 461
7.7.1 重定位条目 461
7.7.2 重定位符号引用 462
7.8 可执行目标文件 465
7.9 加载可执行目标文件 466
7.10 动态链接共享库 467
7.11 从应用程序中加载和链接共享库 468
7.12 与位置无关的代码(PIC)471
7.13 处理目标文件的工具 473
7.14 小结 473
参考文献说明 474
家庭作业 474
练习题答案 479
第 8 章 异常控制流 480
8.1 异常 481
8.1.1 异常处理 481
8.1.2 异常的类别 482
8.1.3 Linux/IA32 系统中的异常 484
8.2 进程 487
8.2.1 逻辑控制流 487
8.2.2 并发流 487
8.2.3 私有地址空间 488
8.2.4 用户模式和内核模式 488
8.2.5 上下文切换 489
8.3 系统调用错误处理 491
8.4 进程控制 492
8.4.1 获取进程 ID492
8.4.2 创建和终止进程 492
8.4.3 回收子进程 495
8.4.4 让进程休眠 499
8.4.5 加载并运行程序 500
8.4.6 利用 fork 和 execve 运行程序 502
8.5 信号 504
8.5.1 信号术语 505
8.5.2 发送信号 506
8.5.3 接收信号 509
8.5.4 信号处理问题 511
8.5.5 可移植的信号处理 516
8.5.6 显式地阻塞和取消阻塞信号 517
8.5.7 同步流以避免讨厌的并发错误 517
8.6 非本地跳转 521
8.7 操作进程的工具 524
8.8 小结 524
参考文献说明 525
家庭作业 525
练习题答案 530
第 9 章 虚拟存储器 534
9.1 物理和虚拟寻址 535
9.2 地址空间 535
9.3 虚拟存储器作为缓存的工具 536
9.3.1 DRAM 缓存的组织结构 537
9.3.2 页表 537
9.3.3 页命中 538
9.3.4 缺页 538
9.3.5 分配页面 539
9.3.6 又是局部性救了我们 539
9.4 虚拟存储器作为存储器管理的工具 540
9.5 虚拟存储器作为存储器保护的工具 541
9.6 地址翻译 542
9.6.1 结合高速缓存和虚拟存储器 544
9.6.2 利用 TLB 加速地址翻译 545
9.6.3 多级页表 546
9.6.4 综合:端到端的地址翻译 547
9.7 案例研究:Intel Core i7/Linux 存储器系统 550
9.7.1 Core i7 地址翻译 551
9.7.2 Linux 虚拟存储器系统 554
9.8 存储器映射 556
9.8.1 再看共享对象 557
9.8.2 再看 fork 函数 558
9.8.3 再看 execve 函数 559
9.8.4 使用 mmap 函数的用户级存储器映射 559
9.9 动态存储器分配 561
9.9.1 malloc 和 free 函数 561
9.9.2 为什么要使用动态存储器分配 563
9.9.3 分配器的要求和目标 564
9.9.4 碎片 565
9.9.5 实现问题 565
9.9.6 隐式空闲链表 565
9.9.7 放置已分配的块 567
9.9.8 分割空闲块 567
9.9.9 获取额外的堆存储器 567
9.9.10 合并空闲块 568
9.9.11 带边界标记的合并 568
9.9.12 综合:实现一个简单的分配器 570
9.9.13 显式空闲链表 576
9.9.14 分离的空闲链表 576
9.10 垃圾收集 578
9.10.1 垃圾收集器的基本知识 579
9.10.2 Mark&Sweep 垃圾收集器 580
9.10.3 C 程序的保守 Mark&Sweep580
9.11 C 程序中常见的与存储器有关的错误 581
9.11.1 间接引用坏指针 582
9.11.2 读未初始化的存储器 582
9.11.3 允许栈缓冲区溢出 582
9.11.4 假设指针和它们指向的对象是相同大小的 583
9.11.5 造成错位错误 583
9.11.6 引用指针,而不是它所指向的对象 583
9.11.7 误解指针运算 584
9.11.8 引用不存在的变量 584
9.11.9 引用空闲堆块中的数据 584
9.11.10 引起存储器泄漏 585
9.12 小结 585
参考文献说明 586
家庭作业 586
练习题答案 589
第三部分 程序间的交互和通信
第 10 章 系统级 I/O596
10.1 Unix I/O596
10.2 打开和关闭文件 597
10.3 读和写文件 598
10.4 用 RIO 包健壮地读写 599
10.4.1 RIO 的无缓冲的输入输出函数 600
10.4.2 RIO 的带缓冲的输入函数 600
10.5 读取文件元数据 604
10.6 共享文件 606
10.7 I/O 重定向 608
10.8 标准 I/O609
10.9 综合:我该使用哪些 I/O 函数 610
10.10 小结 611
参考文献说明 612
家庭作业 612
练习题答案 612
第 11 章 网络编程 614
11.1 客户端-服务器编程模型 614
11.2 网络 615
11.3 全球 IP 因特网 618
11.3.1 IP 地址 619
11.3.2 因特网域名 620
11.3.3 因特网连接 623
11.4 套接字接口 625
11.4.1 套接字地址结构 625
11.4.2 socket 函数 626
11.4.3 connect 函数 626
11.4.4 open_clientfd 函数 627
11.4.5 bind 函数 628
11.4.6 listen 函数 628
11.4.7 open_listenfd 函数 628
11.4.8 accept 函数 629
11.4.9 echo 客户端和服务器的示例 630
11.5 Web 服务器 633
11.5.1 Web 基础 633
11.5.2 Web 内容 633
11.5.3 HTTP 事务 634
11.5.4 服务动态内容 636
11.6 综合:TINY Web 服务器 639
11.7 小结 645
参考文献说明 645
家庭作业 646
练习题答案 646
第 12 章 并发编程 648
12.1 基于进程的并发编程 649
12.1.1 基于进程的并发服务器 649
12.1.2 关于进程的优劣 651
12.2 基于 I/O 多路复用的并发编程 651
12.2.1 基于 I/O 多路复用的并发事件驱动服务器 653
12.2.2 I/O 多路复用技术的优劣 657
12.3 基于线程的并发编程 657
12.3.1 线程执行模型 657
12.3.2 Posix 线程 658
12.3.3 创建线程 659
12.3.4 终止线程 659
12.3.5 回收已终止线程的资源 660
12.3.6 分离线程 660
12.3.7 初始化线程 660
12.3.8 一个基于线程的并发服务器 661
12.4 多线程程序中的共享变量 662
12.4.1 线程存储器模型 663
12.4.2 将变量映射到存储器 663
12.4.3 共享变量 664
12.5 用信号量同步线程 664
12.5.1 进度图 667
12.5.2 信号量 668
12.5.3 使用信号量来实现互斥 669
12.5.4 利用信号量来调度共享资源 670
12.5.5 综合:基于预线程化的并发服务器 674
12.6 使用线程提高并行性 676
12.7 其他并发问题 680
12.7.1 线程安全 680
12.7.2 可重入性 682
12.7.3 在线程化的程序中使用已存在的库函数 682
12.7.4 竞争 683
12.7.5 死锁 685
12.8 小结 687
参考文献说明 687
家庭作业 688
练习题答案 691
附录 A 错误处理 694
A.1 Unix 系统中的错误处理 694
A.2 错误处理包装函数 696
参考文献 698
其他
- 出版社:机械工业出版社
- 丛 书:计算机科学丛书
- 副标题:
- 原作名:Computer Systems: A Programmer's Perspective
- 出版年:2011-1-1
- 总页数:702
- 定 价:99.00 元
- 装 帧:平装
- ISBN:9787111321330
关于『书单』
书单是黑客派社区的一个纸质书共享活动,所有书均来自捐赠,原则上当前的书籍持有者有义务将书寄送给需要的会员。我们鼓励你在书籍上留下笔迹,任何信息都行,让其他人可以看到一些有意思的内容也是蛮不错的 😅
共享意味着什么
一旦你共享了一本书,就会使用你的社区账号自动发一篇书籍共享帖,这意味着你做了一个承诺:将书送到需要的人手中。如果有同城的书籍需求者回帖,就面交吧!
如何参与
- 使用微信扫描如下二维码,进入黑客派社区小程序
- 按照小程序的指引开始即可
一点思考
类似共享书籍的事情有很多人做过,比如:
- 摆摆书架
- 青番茄
- 书巢
- 丢书大作战
- 很多社区的书籍交换
大家的出发点都是想让这个世界变得更好。黑客派的『书单』将作为长期活动持续下去,大家随时都能参与进来,让你我的生活变得更丰富有趣!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于