1. 程式人生 > >《深入理解並行程式設計》中文版

《深入理解並行程式設計》中文版

本書是linux核心大牛paul的力作,和魯陽同學一起,花了兩個月時間進行翻譯。
目前沒有翻譯問答部分,主要是時間不夠,也擔心不能將這部分翻譯準確。
對核心深度發燒的同學可以看看。

本書目錄

1. 簡介…………………………………………………………………………………………… 14

1.1. 導致並行程式設計困難的歷史原因……………………………………………… 14

1.2. 並行程式設計的目標…………………………………………………………………… 15

1.2.1. 效能………………………………………………………………………………. 16

1.2.2. 生產率…………………………………………………………………………… 17

1.2.3. 通用性…………………………………………………………………………… 18

1.3. 並行程式設計的替代方案……………………………………………………………. 20

1.3.1. 順序應用多例項化…………………………………………………………. 20

1.3.2.使用現有的並行軟體……………………………………………………… 21

1.3.3. 效能優化……………………………………………………………………….. 21

1.4. 是什麼使並行程式設計變得複雜?……………………………………………… 22

1.4.1. 工作分割……………………………………………………………………….. 22

1.4.2. 並行訪問控制………………………………………………………………… 23

1.4.3. 資源分割和複製…………………………………………………………….. 24

1.4.4. 與硬體互動……………………………………………………………………. 24

1.4.5. 組合使用……………………………………………………………………….. 24

1.4.6. 語言和環境如何對這樣的任務進行支援?……………………… 25

1.5. 本書導讀……………………………………………………………………………… 25

1.5.1. 小問題…………………………………………………………………………… 25

1.5.2. 隨書原始碼……………………………………………………………………….. 26

2. 硬體的習性………………………………………………………………………………… 28

2.1. 概述…………………………………………………………………………………….. 28

2.1.1. CPU流水線 …………………………………………………………………… 29

2.1.2. 記憶體引用……………………………………………………………………….. 30

2.1.3. 原子操作……………………………………………………………………….. 31

2.1.4. 記憶體屏障……………………………………………………………………….. 32

2.1.5. Cache Miss …………………………………………………………………….. 33

2.1.6. I/O操作 ………………………………………………………………………… 34

2.2. 開銷…………………………………………………………………………………….. 35

2.2.1. 硬體體系結構………………………………………………………………… 36

2.2.2. 操作的開銷……………………………………………………………………. 37

2.3. 硬體的免費午餐? …………………………………………………………………. 38

2.3.1. 3D整合 …………………………………………………………………………. 39

2.3.2. 新材料和新工藝…………………………………………………………….. 39

2.3.3. 專用加速器……………………………………………………………………. 39

2.3.4. 現有的並行軟體…………………………………………………………….. 40

2.4. 軟體設計Implication ……………………………………………………………. 40

3. 工具…………………………………………………………………………………………… 43

3.1. 指令碼語言……………………………………………………………………………… 43

3.2. POSIX多程序 ……………………………………………………………………… 44

3.2.1. POSIX程序建立和撤銷 …………………………………………………. 44

3.2.2. POSIX執行緒的建立和撤銷 ……………………………………………… 46

3.2.3. POSIX鎖 ………………………………………………………………………. 48

3.2.4. POSIX讀寫鎖 ……………………………………………………………….. 52

3.3. 原子操作……………………………………………………………………………… 55

3.4. Linux核心中類似POSIX的操作 …………………………………………. 56

3.5. 趁手的工具——該如何選擇?……………………………………………… 58

4. 計數…………………………………………………………………………………………… 59

4.1. 為什麼併發計數不可小看?…………………………………………………. 60

4.2. 統計計數器………………………………………………………………………….. 62

4.2.1. 設計………………………………………………………………………………. 62

4.2.2. 基於陣列的實現…………………………………………………………….. 62

4.2.3. 結果一致的實現…………………………………………………………….. 64

4.2.4. 基於每執行緒變數的實現………………………………………………….. 66

4.2.5. 討論………………………………………………………………………………. 69

4.3. 近似上限計數器…………………………………………………………………… 69

4.3.1. 設計………………………………………………………………………………. 69

4.3.2. 簡單的上限計數器實現………………………………………………….. 70

4.3.3. 關於簡單上限計數器的討論…………………………………………… 76

4.3.4. 近似上限計數器的實現………………………………………………….. 76

4.3.5. 關於近似上限計數器的討論…………………………………………… 77

4.4. 精確上限計數器…………………………………………………………………… 77

4.4.1. 原子上限計數器的實現………………………………………………….. 77

4.4.2. 關於原子上限計數器的討論…………………………………………… 86

4.4.3. Signal-Theft上限計數器的設計 ……………………………………… 86

4.4.4. Signal-Theft上限計數器的實現 ……………………………………… 87

4.4.5. Signal-Theft上限計數器討論 …………………………………………. 94

4.5. 特殊的並行計數器……………………………………………………………….. 95

4.6. 並行計數的討論…………………………………………………………………… 96

5. 分割和同步設計……………………………………………………………………….. 100

5.1. 分割練習……………………………………………………………………………. 100

5.1.1. 哲學家就餐問題…………………………………………………………… 100

5.1.2. 雙端佇列……………………………………………………………………… 102

5.1.3. 關於分割問題示例的討論…………………………………………….. 111

5.2. 設計準則……………………………………………………………………………. 111

5.3. 同步粒度……………………………………………………………………………. 113

5.3.1. 序列程式……………………………………………………………………… 114

5.3.2. 程式碼鎖…………………………………………………………………………. 116

5.3.3. 資料鎖…………………………………………………………………………. 117

5.3.4. 資料所有權………………………………………………………………….. 120

5.3.5. 鎖粒度與效能………………………………………………………………. 121

5.4. 並行快速路徑…………………………………………………………………….. 121

5.4.1. 讀寫鎖…………………………………………………………………………. 122

5.4.2. 層級鎖…………………………………………………………………………. 123

5.4.3. 資源分配器快取…………………………………………………………… 125

5.5. 效能總結……………………………………………………………………………. 131

6. 鎖…………………………………………………………………………………………….. 132

6.1. 生存(staying alive) …………………………………………………………. 133

6.1.1. 死鎖…………………………………………………………………………….. 133

6.1.2. 活鎖…………………………………………………………………………….. 136

6.1.3. 不公平…………………………………………………………………………. 137

6.1.4. 低效率…………………………………………………………………………. 137

6.2. 鎖的型別……………………………………………………………………………. 137

6.2.1. 互斥鎖…………………………………………………………………………. 138

6.2.2. 讀寫鎖…………………………………………………………………………. 138

6.2.3. Beyond Reader-Writer Locks …………………………………………. 138

6.3. 基於鎖的存在擔保(existence guarantee) ………………………….. 138

7. 資料所有者………………………………………………………………………………. 140

8. 延遲處理………………………………………………………………………………….. 142

8.1. 屏障…………………………………………………………………………………… 142

8.2. 引用計數……………………………………………………………………………. 142

8.2.1. 引用計數型別的實現……………………………………………………. 143

8.2.2. 支援引用計數的Linux原語 …………………………………………. 150

8.2.3. 計數器優化………………………………………………………………….. 151

8.3. Read-Copy Update(RCU)………………………………………………… 151

8.3.1. RCU基礎 ……………………………………………………………………. 151

8.3.2. RCU用法 ……………………………………………………………………. 163

8.3.3. Linux核心中的RCU API……………………………………………… 176

8.3.4. “玩具式”的RCU實現 ……………………………………………… 183

8.3.5. RCU練習 ……………………………………………………………………. 206

9. 使用RCU ………………………………………………………………………………… 207

9.1. RCU和基於每執行緒變數的統計計數器 ……………………………….. 207

9.1.1. 設計…………………………………………………………………………….. 207

9.1.2. 實現…………………………………………………………………………….. 207

9.1.3. 討論…………………………………………………………………………….. 211

9.2. RCU和可移除I/O裝置的計數器 ……………………………………….. 211

10. 驗證:除錯及分析……………………………………………………………………. 214

11. 資料結構………………………………………………………………………………….. 216

12. 高階同步………………………………………………………………………………….. 218

12.1. 避免鎖……………………………………………………………………………….. 218

12.2. 記憶體屏障……………………………………………………………………………. 218

12.2.1. 記憶體序及記憶體屏障…………………………………………………. 218

12.2.2. 如果B在A後面, 並且C在B後面, 為什麼C不在A後面? 220

12.2.3. 變數可以擁有多個值……………………………………………… 221

12.2.4. 能信任什麼東西? …………………………………………………… 222

12.2.5. 鎖實現回顧……………………………………………………………. 229

12.2.6. 一些簡單的規則…………………………………………………….. 230

12.2.7. 抽象記憶體訪問模型…………………………………………………. 230

12.2.8. 裝置操作……………………………………………………………….. 233

12.2.9. 保證………………………………………………………………………. 233

12.2.10. 什麼是記憶體屏障? …………………………………………………… 234

12.2.11. 鎖約束…………………………………………………………………… 247

12.2.12. 記憶體屏障示例………………………………………………………… 248

12.2.13. CPU ………………………………………………………………………. 251

12.2.14. 哪裡需要記憶體屏障? ……………………………………………….. 253

12.3. 非阻塞同步………………………………………………………………………… 253

12.3.1. 簡單 NBS ……………………………………………………………… 253

12.3.2. 冒險指標……………………………………………………………….. 253

12.3.3. 原子資料結構………………………………………………………… 253

12.3.4. “Macho” NBS………………………………………………………… 253

13. 易於使用………………………………………………………………………………….. 254

13.1. Rusty Scale for API Design ………………………………………………….. 254

13.2. Shaving the Mandelbrot Set ………………………………………………….. 255

14. 時間管理………………………………………………………………………………….. 258

15. 未來的衝突………………………………………………………………………………. 259

15.1. 可交易記憶體………………………………………………………………………… 259

15.1.1. I/O 操作 ……………………………………………………………….. 260

15.1.2. RPC 操作 ……………………………………………………………… 260

15.1.3. 記憶體對映操作………………………………………………………… 261

15.1.4. 多執行緒事務……………………………………………………………. 262

15.1.5. 外部的事務訪問…………………………………………………….. 263

15.1.6. 延時………………………………………………………………………. 264

15.1.7. 鎖………………………………………………………………………….. 264

15.1.8. 讀者-寫者鎖 ………………………………………………………….. 265

15.1.9. 持續性…………………………………………………………………… 266

TM如何提供類似的持續性功能?……………………………………………………….. 266

15.1.10. 動態連結裝載………………………………………………………… 266

15.1.11. 除錯………………………………………………………………………. 267

15.1.12. exec() 系統呼叫…………………………………………………….. 268

15.1.13. RCU ……………………………………………………………………… 268

15.1.14. 討論………………………………………………………………………. 270

15.2. 共享記憶體並行程式設計……………………………………………………………… 270

15.3. 基於任務的並行程式設計………………………………………………………….. 270

A. 重要問題………………………………………………………………………………….. 271

A.1 “after“的含義是什麼? …………………………………………………………. 271

B. 同步原語………………………………………………………………………………….. 277

B.1 初始化……………………………………………………………………………….. 277

B.1.1 smp_init() …………………………………………………………………….. 277

B.2 執行緒建立、銷燬及控制………………………………………………………. 278

B.2.1 create_thread() ……………………………………………………………… 278

B.2.2 smp_thread_id() ……………………………………………………………. 278

B.2.3 for_each_thread() ………………………………………………………….. 278

B.2.4 for_each_running_thread() …………………………………………….. 279

B.2.5 wait_thread() ………………………………………………………………… 279 深入理解並行程式設計

B.2.6 wait_all_threads() …………………………………………………………. 279

B.2.7 用法示例……………………………………………………………….. 279

B.3 鎖………………………………………………………………………………………. 280

B.3.1 spin_lock_init() …………………………………………………………….. 280

B.3.2 spin_lock() …………………………………………………………………… 280

B.3.3 spin_trylock() ……………………………………………………………….. 281

B.3.4 spin_unlock() ……………………………………………………………….. 281

B.3.5 用法示例……………………………………………………………….. 281

B.4 每執行緒變數………………………………………………………………………… 281

B.4.1 DEFINE_PER_THREAD() ……………………………………………. 282

B.4.2 DECLARE_PER_THREAD() ………………………………………… 282

B.4.3 per_thread() ………………………………………………………………….. 282

B.4.4 __get_thread_var() ………………………………………………………… 282

B.4.5 init_per_thread() …………………………………………………………… 282

B.4.6 用法示例……………………………………………………………….. 282

B.5 效能…………………………………………………………………………………… 283

C. 為什麼使用記憶體屏障………………………………………………………………… 284

C.1 Cache 結構………………………………………………………………………… 284

C.2 快取一致性協議…………………………………………………………………. 286

C.2.1 MESI 狀態 ………………………………………………………………….. 286

C.2.2 MESI 協議訊息 …………………………………………………………… 287

C.2.3 MESI狀態圖 ……………………………………………………………….. 288

C.2.4 MESI 協議示例 …………………………………………………………… 289

C.3 不必要的儲存延遲……………………………………………………………… 291

C.3.1 Store Buffers ………………………………………………………………… 291

C.3.2 Store Forwarding ………………………………………………………….. 292

C.3.3 儲存緩衝區及記憶體屏障………………………………………….. 293

C.4 不必要的儲存延遲……………………………………………………………… 296

C.4.1 無效佇列……………………………………………………………….. 296

C.4.2 使無效佇列及使無效應答………………………………………. 296

C.4.3 無效佇列及記憶體屏障……………………………………………… 297

C.5 讀和寫記憶體屏障…………………………………………………………………. 300

C.6 記憶體屏障示例…………………………………………………………………….. 300

C.6.1 亂序體系結構………………………………………………………… 300

C.6.2 示例 1 …………………………………………………………………… 301 深入理解並行程式設計

C.6.3 示例 2 …………………………………………………………………… 302

C.6.4 示例 3 …………………………………………………………………… 303

C.7 特定CPUs的記憶體屏障指令 ……………………………………………….. 304

C.7.1 Alpha …………………………………………………………………………… 306

C.7.2 AMD64 ……………………………………………………………………….. 308

C.7.3 ARMv7-A/R ………………………………………………………………… 309

6 ISB();………………………………………………………………………………………………… 309

C.7.4 IA64 ……………………………………………………………………………. 309

C.7.5 PA-RISC ………………………………………………………………………. 310

C.7.6 POWER / Power PC ……………………………………………………… 310

C.7.7 SPARC RMO, PSO, and TSO ………………………………………… 311

C.7.8 x86………………………………………………………………………………. 312

C.7.9 zSeries …………………………………………………………………………. 313

C.8 記憶體屏障是永恆的? ……………………………………………………………. 313

C.9 對硬體設計者的建議………………………………………………………….. 314

D. RCU實現 ………………………………………………………………………………… 315

D.1 可睡眠 RCU 實現 ……………………………………………………………… 315

D.1.1 SRCU 實現原理 ………………………………………………………….. 316

D.1.2 SRCU API 及用法 ……………………………………………………….. 317

D.1.3 實現………………………………………………………………………. 320

D.1.4 SRCU 概述 …………………………………………………………………. 326

D.2 分級 RCU 概述 ………………………………………………………………… 326

D.2.1 RCU 基礎回顧 ……………………………………………………………. 326

D.2.2 經典 RCU 實現概要 ……………………………………………… 327

D.2.3 RCU 迫切要解決的問題 ………………………………………………. 328

D.2.4 可擴充套件RCU 實現 ………………………………………………….. 329

D.2.5 邁向不成熟的RCU 實現 ……………………………………….. 332

D.2.6 狀態機…………………………………………………………………… 334

D.2.7 用例………………………………………………………………………. 335

D.2.8 測試………………………………………………………………………. 340

D.2.9 結論………………………………………………………………………. 345

D.3 分級 RCU程式碼走查 …………………………………………………………… 346

D.3.1 資料結構及核心引數……………………………………………… 346

D.3.2 外部介面……………………………………………………………….. 354

D.3.3 初始化…………………………………………………………………… 362 深入理解並行程式設計

D.3.4 CPU 熱插撥 ………………………………………………………………… 367

D.3.5 雜項函式……………………………………………………………….. 372

D.3.6 Grace-Period檢測函式 …………………………………………………. 373

D.3.7 Dyntick-Idle 函式 ………………………………………………………… 385

D.3.8 強制靜止狀態………………………………………………………… 390

D.3.9 CPU-延遲檢測 …………………………………………………………….. 397

D.3.10 可能的缺陷及變更…………………………………………………. 400

D.4 可搶佔 RCU ……………………………………………………………………… 400

D.4.1 RCU概念 ……………………………………………………………………. 401

D.4.2 可搶佔RCU演算法概述 …………………………………………… 402

D.4.3 驗證可搶佔 RCU …………………………………………………… 419

E. 形式驗證………………………………………………………………………………….. 422

E.1 什麼是 Promela 和 Spin? ………………………………………………….. 422

E.2 Promela 示例: 非原子性遞增 …………………………………………….. 423

E.3 Promela 示例: 原子遞增 ……………………………………………………. 426

E.3.1 組合…………………………………………………………………………….. 427

E.4 如何使用 Promela ……………………………………………………………… 428

E.4.1 Promela 特性 ………………………………………………………………. 428

E.4.2 Promela程式設計技巧 ………………………………………………………… 429

E.5 Promela 示例: 鎖 ………………………………………………………………. 430

E.6 Promela 示例: QRCU …………………………………………………………. 433

E.6.1 執行 QRCU 示例 ……………………………………………………….. 438

E.6.2 到底需要多少讀者和寫者? …………………………………………… 439

E.6.3 可選方法: 正確性校驗 …………………………………………………. 439

E.6.4 可選方法: 更多工具 …………………………………………………….. 440

E.6.5 可選方法: 分而治之 …………………………………………………….. 440

E.7 Promela Parable: dynticks 和可搶佔 RCU …………………………… 440

E.7.1 可搶佔 RCU 和 dynticks介紹 …………………………………….. 441

E.7.2 驗證可搶佔RCU和dynticks ………………………………………… 445

E.7.3 回顧…………………………………………………………………………….. 466

E.8 簡單的避免形式校驗………………………………………………………….. 467

E.8.1 簡單Dynticks 介面的狀態變數 ……………………………………. 467

E.8.2 進入和退出Dynticks-Idle 模式…………………………………….. 468

E.8.3 從Dynticks-Idle 模式進入NMIs ………………………………….. 469

E.8.4 Interrupts From Dynticks-Idle Mode ……………………………….. 470

E.8.5 檢查Dynticks 靜止狀態 ………………………………………………. 471

E.8.6 討論…………………………………………………………………………….. 473

E.9 概要…………………………………………………………………………………… 473

F. 問題答案………………………………………………………………………………….. 474

G. 術語表……………………………………………………………………………………… 475

H. 感謝…………………………………………………………………………………………. 476


謝 寶友

謝寶友:畢業於四川省稅務學校稅收專業,現供職於中興通訊作業系統團隊,對作業系統核心有較強的興趣。專職於作業系統核心已經有四年時間。目標是利用十年時間,成為一名真正的“核心菜鳥”。個人主頁是:http://xiebaoyou.blog.chinaunix.net。