Linux多執行緒服務端編程:使用muduo C++網路庫

Linux多執行緒服務端編程:使用muduo C++網路庫

《Linux多執行緒服務端編程:使用muduo C++網路庫》主要講述採用現代C++在x86-64 Linux上編寫多執行緒TCP網路服務程式的主流常規技術,重點講解一種適應性較強的多執行緒伺服器的編程模型,即one loop per thread。

內容簡介

本書主要講述採用現代C++在x86-64 Linux上編寫多執行緒TCP網路服務程式的主流常規技術,重點講解一種適應性較強的多執行緒伺服器的編程模型,即one loop per thread。這是在Linux下以native語言編寫用戶態高性能網路程式最成熟的模式,掌握之後可順利地開發各類常見的服務端網路應用程式。本書以muduo網路庫為例,講解這種編程模型的使用方法及注意事項。

本書的宗旨是貴精不貴多。掌握兩種基本的同步原語就可以滿足各種多執行緒同步的功能需求,還能寫出更易用的同步設施。掌握一種進程間通信方式和一種多執行緒網路編程模型就足以應對日常開發任務,編寫運行於公司區域網路環境的分散式服務系統。

書本目錄

第1部分C++ 多執行緒系統編程

第1章執行緒安全的對象生命期管理3

1.1當析構函式遇到多執行緒. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3

1.1.1執行緒安全的定義. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4

1.1.2MutexLock 與MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4

1.1.3一個執行緒安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4

1.2對象的創建很簡單. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5

1.3銷毀太難. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7

1.3.1mutex 不是辦法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7

1.3.2作為數據成員的mutex 不能保護析構.. . . . . . . . . . . . . . 8

1.4執行緒安全的Observer 有多難.. . . . . . . . . . . . . . . . . . . . . . . . 8

1.5原始指針有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11

1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13

1.7插曲:系統地避免各種指針錯誤. . . . . . . . . . . . . . . . .. . . . . . 14

1.8套用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.9再論shared_ptr 的執行緒安全.. . . . . . . . . . . . . . . . . . . . . . . . 17

1.10shared_ptr 技術與陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19

1.11對象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21

1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23

1.11.2弱回調. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24

1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26

1.13心得與小結. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26

1.14Observer 之謬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

第2章執行緒同步精要

2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

2.1.1隻使用非遞歸的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33

2.1.2死鎖. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35

2.2條件變數(condition variable). . . . . . . . . . . . . . . . . . . . . . . 40

2.3不要用讀寫鎖和信號量. . . . . . . . . . . . . . . . .. . . . . . . . . . . 43

2.4封裝MutexLock、MutexLockGuard、Condition. . . . . . . . . . . . . . 44

2.5執行緒安全的Singleton 實現.. . . . . . . . . . . . . . . . . . . . . . . . . 48

2.6sleep(3) 不是同步原語. . . .. . . . . . . . . . . . . . . . . . . . . . . . 50

2.7歸納與總結. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 51

2.8借shared_ptr 實現copy-on-write. . . . . . . . . . . . . . . . . . . . . . 52

第3章多 執行緒伺服器的適用場合與常用編程模型

3.1進程與執行緒. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 59

3.2單執行緒伺服器的常用編程模型. . . . . . . . . . . . . . . . .. . . . . . . 61

3.3多執行緒伺服器的常用編程模型. . . . . . . . . . . . . . . . .. . . . . . . 62

3.3.1one loop per thread . . . . . . . . . . . . . . . . . . . . . . . . . . 62

3.3.2執行緒池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 63

3.3.3推薦模式. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 64

3.4進程間通信只用TCP . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 65

3.5多執行緒伺服器的適用場合. . . . . . . . . . . . . . . . .. . . . . . . . . . 67

3.5.1必須用單執行緒的場合. . . . . . . . . . . . . . . . .. . . . . . . . 69

3.5.2單執行緒程式的優缺點. . . . . . . . . . . . . . . . .. . . . . . . . 70

3.5.3適用多執行緒程式的場景. . . . . . . . . . . . . . . . .. . . . . . . 71

3.6“多執行緒伺服器的適用場合”例釋與答疑.. . . . . . . . . . . . . . . . . 74

第4章C++ 多執行緒系統編程精要83

4.1基本執行緒原語的選用. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 84

4.2C/C++ 系統庫的執行緒安全性. . . . . . . . . . . . . . . . .. . . . . . . . 85

4.3Linux 上的執行緒標識. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 89

4.4執行緒的創建與銷毀的守則. . . . . . . . . . . . . . . . .. . . . . . . . . . 91

6pxhread_cancel 與C++ . .. . . . . . . . . . . . . . . . . . . . . 94

4.4.2exit(3) 在C++ 中不是執行緒安全的.. . . . . . . . . . . . . . . . 94

4.5善用__thread 關鍵字.. . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

4.6多執行緒與IO . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 98

4.7用RAII 包裝檔案描述符.. . . . . . . . . . . . . . . . . . . . . . . . . . 99

4.8RAII 與fork() . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 101

4.9多執行緒與fork() . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 102

4.10多執行緒與signal . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 103

4.11Linux 新增系統調用的啟示. . . . . . . . . . . . . . . . .. . . . . . . . . 105

第5章高效的多執行緒日誌107

5.1功能需求. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 109

5.2性能需求. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 112

5.3多執行緒異步日誌. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 114

5.4其他方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 120

第2部分muduo 網路庫

第6章muduo 網路庫簡介125

6.1由來. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . 125

6.2安裝. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . 127

6.3目錄結構. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 129

6.3.1代碼結構. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 131

6.3.2例子. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 134

6.3.3執行緒模型. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 135

6.4使用教程. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 136

6.4.1TCP 網路編程本質論. . . . . . . . . . . . . . . . .. . . . . . . . 136

6.4.2echo 服務的實現. . . . . . . . . . . . . . . . . . . .. . . . . . . 138

6.4.3七步實現finger 服務.. . . . . . . . . . . . . . . . . . . . . . . . 140

6.5性能評測. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 144

6.5.1muduo 與Boost.Asio、libevent2的吞吐量對比. . . . . . . . . . 145

6.5.2擊鼓傳花:對比muduo 與libevent2的事件處理效率. . . . . . 148

6.5.3muduo 與Nginx 的吞吐量對比.. . . . . . . . . . . . . . . . . . 153

6.5.4muduo 與ZeroMQ 的延遲對比.. . . . . . . . . . . . . . . . . . 156

6.6詳解muduo 多執行緒模型.. . . . . . . . . . . . . . . . . . . . . . . . . . 157

6.6.1數獨求解伺服器. . . . . . . . . . . . . . . . .. . . . . . . . . . . 157

6.6.2常見的並發網路服務程式設計方案. . . . . . . . . . . . . . . . .160

第7章muduo 編程示例177

7.1五個簡單TCP 示例.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

7.2檔案傳輸. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 185

7.3Boost.Asio 的聊天伺服器. . . .. . . . . . . . . . . . . . . . . . . . . . . 194

7.3.1TCP 分包. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 194

7.3.2訊息格式. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 195

7.3.3編解碼器LengthHeaderCodec . . . . . . . . . . .. . . . . . . . . 197

7.3.4服務端的實現. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 198

7.3.5客戶端的實現. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 200

7.4muduo Buffer 類的設計與使用. . . .. . . . . . . . . . . . . . . . . . . 204

7.4.1muduo 的IO 模型.. . . . . . . . . . . . . . . . . . . . . . . . . 204

7.4.2為什麼non-blocking 網路編程中套用層buffer是必需的. . . . 205

7.4.3Buffer 的功能需求. . . . . . . . . . . . . . . . . . . .. . . . . . 207

7.4.4Buffer 的數據結構. . . . . . . . . . . . . . . . . . . .. . . . . . 209

7.4.5Buffer 的操作. . . . . . . . . . . . . . . . . . . .. . . . . . . . . 211

7.4.6其他設計方案. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 217

7.4.7性能是不是問題. . . . . . . . . . . . . . . . .. . . . . . . . . . . 218

7.5一種自動反射訊息類型的Google Protobuf 網路傳輸方案.. . . . . . . 220

7.5.1網路編程中使用Protobuf 的兩個先決條件.. . . . . . . . . . . . 220

7.5.2根據type name 反射自動創建Message對象. . . . . . . . . . . . 221

7.5.3Protobuf 傳輸格式. . . .. . . . . . . . . . . . . . . . . . . . . . 226

7.6在muduo 中實現Protobuf編解碼器與訊息分發器. . . . . . . . . . . . 228

7.6.1什麼是編解碼器(codec). . . . . . . . . . . . . . . . . . . . . . 229

7.6.2實現ProtobufCodec . . . . . . . . . . . . .. . . . . . . . . . . . 232

7.6.3訊息分發器(dispatcher)有什麼用.. . . . . . . . . . . . . . . 232

7.6.4ProtobufCodec 與ProtobufDispatcher的綜合運用. . . . . . . 233

7.6.5ProtobufDispatcher 的兩種實現. . . .. . . . . . . . . . . . . . 234

7.6.6ProtobufCodec 和ProtobufDispatcher有何意義. . . . . . . . . 236

7.7限制伺服器的最大並發連線數. . . . . . . . . . . . . . . . .. . . . . . . 237

7.7.1為什麼要限制並發連線數. . . . . . . . . . . . . . . . .. . . . . 237

7.7.2在muduo 中限制並發連線數.. . . . . . . . . . . . . . . . . . . 238

7.8定時器. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 240

7.8.1程式中的時間. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 240

7.8.2Linux 時間函式. . . . . . . . . . . . . . . . . . . .. . . . . . . . 241

7.8.3muduo 的定時器接口. . . . . . . . . . . . . . . . .. . . . . . . . 242

7.8.4Boost.Asio Timer 示例. . . .. . . . . . . . . . . . . . . . . . . . 243

7.8.5Java Netty 示例. . . .. . . . . . . . . . . . . . . . . . . . . . . . 245

7.9測量兩台機器的網路延遲和時間差. . . . . . . . . . . . . . . . .. . . . 248

7.10用timing wheel 踢掉空閒連線.. . . . . . . . . . . . . . . . . . . . . . . 250

7.10.1timing wheel 原理. . . .. . . . . . . . . . . . . . . . . . . . . . 251

7.10.2代碼實現與改進. . . . . . . . . . . . . . . . .. . . . . . . . . . . 254

7.11簡單的訊息廣播服務. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 257

7.12“串並轉換”連線伺服器及其自動化測試.. . . . . . . . . . . . . . . . . 260

7.13socks4a 代理伺服器. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . 264

7.13.1TCP 中繼器. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . 264

7.13.2socks4a 代理伺服器. . . .. . . . . . . . . . . . . . . . . . . . . . 267

7.13.3N : 1 與1 : N 連線轉發.. . . . . . . . . . . . . . . . . . . . . . . 267

7.14短址服務. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 267

7.15與其他庫集成. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 268

7.15.1UDNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270

7.15.2c-ares DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

7.15.3curl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273

7.15.4更多. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 275

第8章muduo 網路庫設計與實現277

8.0什麼都不做的EventLoop . . . . . . . . . . . .. . . . . . . . . . . . . . . 277

8.1Reactor 的關鍵結構. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . 280

8.1.1Channel class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280

8.1.2Poller class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283

8.1.3EventLoop 的改動. . . .. . . . . . . . . . . . . . . . . . . . . . . 287

8.2TimerQueue 定時器. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . 290

8.2.1TimerQueue class . . . . . . . . . . . . . . . . . . . . . . . . . . . 290

8.2.2EventLoop 的改動. . . .. . . . . . . . . . . . . . . . . . . . . . . 292

8.3EventLoop::runInLoop() 函式.. . . . . . . . . . . . . . . . . . . . . . . 293

8.3.1提高TimerQueue 的執行緒安全性.. . . . . . . . . . . . . . . . . . 296

8.3.2EventLoopThread class . . . . . . . . . . . . . . . . . . . . . . . . 297

8.4實現TCP 網路庫.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

8.5TcpServer 接受新連線. . . .. . . . . . . . . . . . . . . . . . . . . . . . 303

8.5.1TcpServer class . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

8.5.2TcpConnection class . . . . . . . . . . . . . . . . . . . . . . . . . 305

8.6TcpConnection 下線. . . .. . . . . . . . . . . . . . . . . . . . . . . 308

8.7Buffer 讀取數據. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 313

8.7.1TcpConnection 使用Buffer 作為輸入緩衝.. . . . . . . . . . . . 314

8.7.2Buffer::readFd() . . . . . . . . . . . . . . . . . . . . . . . . . . 315

8.8TcpConnection 傳送數據. . . .. . . . . . . . . . . . . . . . . . . . . . . 316

8.9完善TcpConnection . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 320

8.9.1SIGPIPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321

8.9.2TCP No Delay 和TCPkeepalive . . . . . . . . . . . . . . . . . . 321

8.9.3WriteCompleteCallback 和HighWaterMarkCallback. . . . . . . 322

8.10多執行緒TcpServer . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 324

8.11Connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .327

8.12TcpClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332

8.13epoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 333

8.14測試程式一覽. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 336

第3部分工程實踐經驗談

第9章分散式系統工程實踐339

9.1我們在技術浪潮中的位置. . . . . . . . . . . . . . . . .. . . . . . . . . . 341

9.1.1分散式系統的本質困難. . . . . . . . . . . . . . . . .. . . . . . . 343

9.1.2分散式系統是個險惡的問題. . . . . . . . . . . . . . . . .. . . . 344

9.2分散式系統的可靠性淺說. . . . . . . . . . . . . . . . .. . . . . . . . . . 349

9.2.1分散式系統的軟體不要求7 [1] 24 可靠.. . . . . . . . . . . . . . . 352

9.2.2“能隨時重啟進程”作為程式設計目標.. . . . . . . . . . . . . . 354

9.3分散式系統中心跳協定的設計. . . . . . . . . . . . . . . . .. . . . . . . 356

9.4分散式系統中的進程標識. . . . . . . . . . . . . . . . .. . . . . . . . . . 360

9.4.1錯誤做法. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 361

9.4.2正確做法. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 362

9.4.3TCP 協定的啟示. . . . . . . . . . . . . . . . . . . .. . . . . . . . 363

9.5構建易於維護的分散式程式. . . . . . . . . . . . . . . . .. . . . . . . . 364

9.6為系統演化做準備. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 367

9.6.1可擴展的訊息格式. . . . . . . . . . . . . . . . .. . . . . . . . . 368

9.6.2反面教材:ICE 的訊息打包格式.. . . . . . . . . . . . . . . . . . 369

9.7分散式程式的自動化回歸測試. . . . . . . . . . . . . . . . .. . . . . . . 370

9.7.1單元測試的能與不能. . . . . . . . . . . . . . . . .. . . . . . . . 370

9.7.2分散式系統測試的要點. . . . . . . . . . . . . . . . .. . . . . . . 373

9.7.3分散式系統的抽象觀點. . . . . . . . . . . . . . . . .. . . . . . . 374

9.7.4一種自動化的回歸測試方案. . . . . . . . . . . . . . . . .. . . . 375

9.7.5其他用處. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 379

9.8分散式系統部署、監控與進程管理的幾重境界. . . .. . . . . . . . . . . 380

9.8.1境界1:全手工操作.. . . . . . . . . . . . . . . . . . . . . . . . 382

9.8.2境界2:使用零散的自動化腳本和第三方組件.. . . . . . . . . . 383

9.8.3境界3:自製機群管理系統,集中化配置.. . . . . . . . . . . . 386

9.8.4境界4:機群管理與namingservice 結合. . . .. . . . . . . . . 389

第10章C++ 編譯連結模型精要391

10.1C 語言的編譯模型及其成因. . . . . . . . . . . . . . . . .. . . . . . . . 394

10.1.1為什麼C 語言需要預處理.. . . . . . . . . . . . . . . . . . . . . 395

10.1.2C 語言的編譯模型. . . . . . . . . . . . . . . . .. . . . . . . . . . 398

10.2C++ 的編譯模型. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 399

10.2.1單遍編譯. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 399

10.2.2前向聲明. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 402

10.3C++ 連結(linking). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404

10.3.1函式重載. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 406

10.3.2inline 函式. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . 407

10.3.3模板. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 409

10.3.4虛函式. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 414

10.4工程項目中頭檔案的使用規則. . . . . . . . . . . . . . . . .. . . . . . . 415

10.4.1頭檔案的害處. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 416

10.4.2頭檔案的使用規則. . . . . . . . . . . . . . . . .. . . . . . . . . 417

10.5工程項目中庫檔案的組織原則. . . . . . . . . . . . . . . . .. . . . . . . 418

10.5.1動態庫是有害的. . . . . . . . . . . . . . . . .. . . . . . . . . . . 423

10.5.2靜態庫也好不到哪兒去. . . . . . . . . . . . . . . . .. . . . . . . 424

10.5.3源碼編譯是王道. . . . . . . . . . . . . . . . .. . . . . . . . . . . 428

第11章反思C++ 面向對象與虛函式429

11.1樸實的C++ 設計.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429

11.2程式庫的二進制兼容性. . . . . . . . . . . . . . . . .. . . . . . . . . . . 431

11.2.1什麼是二進制兼容性. . . . . . . . . . . . . . . . .. . . . . . . . 432

11.2.2有哪些情況會破壞庫的ABI . . . . . . . . . . . . . . .. . . . . . 433

11.2.3哪些做法多半是安全的. . . . . . . . . . . . . . . . .. . . . . . . 435

11.2.4反面教材:COM . . . . . . . . . . . . . . . . . .. . . . . . . . . 435

11.2.5解決辦法. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 436

11.3避免使用虛函式作為庫的接口. . . . . . . . . . . . . . . . .. . . . . . . 436

11.3.1C++ 程式庫的作者的生存環境. . . . . . . . . . . . . . . . .. . . 437

11.3.2虛函式作為庫的接口的兩大用途. . . . . . . . . . . . . . . . .. 438

11.3.3虛函式作為接口的弊端. . . . . . . . . . . . . . . . .. . . . . . . 439

11.3.4假如Linux 系統調用以COM接口方式實現. . . . . . . . . . . . 442

11.3.5Java 是如何應對的. . . . . . . . . . . . . . . . .. . . . . . . . . 443

11.4動態庫接口的推薦做法. . . . . . . . . . . . . . . . .. . . . . . . . . . . 443

11.5以boost::function 和boost::bind取代虛函式. . . . . . . . . . . . . 447

11.5.1基本用途. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 450

11.5.2對程式庫的影響. . . . . . . . . . . . . . . . .. . . . . . . . . . . 451

11.5.3對面向對象程式設計的影響. . . . . . . . . . . . . . . . .. . . . 453

11.6iostream 的用途與局限. . . .. . . . . . . . . . . . . . . . . . . . . . . . 457

11.6.1stdio 格式化輸入輸出的缺點. . . . . . . . . . . . . . . . .. . . . 457

11.6.2iostream 的設計初衷. . . .. . . . . . . . . . . . . . . . . . . . . 461

11.6.3iostream 與標準庫其他組件的互動. . . .. . . . . . . . . . . . . 463

11.6.4iostream 在使用方面的缺點. . . .. . . . . . . . . . . . . . . . . 464

11.6.5iostream 在設計方面的缺點. . . .. . . . . . . . . . . . . . . . . 468

11.6.6一個300 行的memorybuffer output stream . . . . . . . . . . . 476

11.6.7現實的C++ 程式如何做檔案IO. . . . . . . . . . . . . . . . . . . 480

11.7值語義與數據抽象. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 482

11.7.1什麼是值語義. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 482

11.7.2值語義與生命期. . . . . . . . . . . . . . . . .. . . . . . . . . . . 483

11.7.3值語義與標準庫. . . . . . . . . . . . . . . . .. . . . . . . . . . . 488

11.7.4值語義與C++ 語言.. . . . . . . . . . . . . . . . . . . . . . . . . 488

11.7.5什麼是數據抽象. . . . . . . . . . . . . . . . .. . . . . . . . . . . 490

11.7.6數據抽象所需的語言設施. . . . . . . . . . . . . . . . .. . . . . 493

11.7.7數據抽象的例子. . . . . . . . . . . . . . . . .. . . . . . . . . . . 495

第12章C++ 經驗談501

12.1用異或來交換變數是錯誤的. . . . . . . . . . . . . . . . .. . . . . . . . 501

12.1.1編譯器會分別生成什麼代碼. . . . . . . . . . . . . . . . .. . . . 503

12.1.2為什麼短的代碼不一定快. . . . . . . . . . . . . . . . .. . . . . 505

12.2不要重載全局::operator new() . . . . . . . .. . . . . . . . . . . . . . 507

12.2.1記憶體管理的基本要求. . . . . . . . . . . . . . . . .. . . . . . . . 507

12.2.2重載::operator new() 的理由.. . . . . . . . . . . . . . . . . . 508

12.2.3::operator new() 的兩種重載方式. . . .. . . . . . . . . . . . . 508

12.2.4現實的開發環境. . . . . . . . . . . . . . . . .. . . . . . . . . . . 509

12.2.5重載::operator new() 的困境.. . . . . . . . . . . . . . . . . . 510

12.2.6解決辦法:替換malloc() . . . . . . . . . . . .. . . . . . . . . . 512

12.2.7為單獨的class 重載::operatornew() 有問題嗎. . . . . . . . . 513

12.2.8有必要自行定製記憶體分配器嗎. . . . . . . . . . . . . . . . .. . . 513

12.3帶符號整數的除法與餘數. . . . . . . . . . . . . . . . .. . . . . . . . . . 514

12.3.1語言標準怎么說. . . . . . . . . . . . . . . . .. . . . . . . . . . . 515

12.3.2C/C++ 編譯器的表現. . . . . . . . . . . . . . . . .. . . . . . . . 516

12.3.3其他語言的規定. . . . . . . . . . . . . . . . .. . . . . . . . . . . 516

12.3.4腳本語言解釋器代碼. . . . . . . . . . . . . . . . .. . . . . . . . 517

12.3.5硬體實現. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 521

12.4在單元測試中mock 系統調用.. . . . . . . . . . . . . . . . . . . . . . . 522

12.4.1系統函式的依賴注入. . . . . . . . . . . . . . . . .. . . . . . . . 522

12.4.2連結期墊片(link seam). . . . . . . . . . . . . . . . . . . . . . 524

12.5慎用匿名namespace . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 526

12.5.1C 語言的static 關鍵字的兩種用法.. . . . . . . . . . . . . . . . 526

12.5.2C++ 語言的static 關鍵字的四種用法.. . . . . . . . . . . . . . . 526

12.5.3匿名namespace 的不利之處.. . . . . . . . . . . . . . . . . . . . 527

12.5.4替代辦法. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 529

12.6採用有利於版本管理的代碼格式. . . . . . . . . . . . . . . . .. . . . . . 529

12.6.1對diff 友好的代碼格式.. . . . . . . . . . . . . . . . . . . . . . . 530

12.6.2對grep 友好的代碼風格.. . . . . . . . . . . . . . . . . . . . . . 537

12.6.3一切為了效率. . . . . . . . . . . . . . . . .. . . . . . . . . . . . 538

12.7再探std::string . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 539

12.7.1直接拷貝(eager copy). . . . . . . . . . . . . . . . . . . . . . . 540

12.7.2寫時複製(copy-on-write). . . . . . . . . . . . . . . . . . . . . 542

12.7.3短字元串最佳化(SSO). . . . . . . . . . . . . . . . . . . . . . . . 543

12.8用STL algorithm 輕鬆解決幾道算法面試題.. . . . . . . . . . . . . . . 546

12.8.1用next_permutation() 生成排列與組合.. . . . . . . . . . . . . 546

12.8.2用unique() 去除連續重複空白.. . . . . . . . . . . . . . . . . . 548

12.8.3用{make,push,pop}_heap() 實現多路歸併.. . . . . . . . . . . 549

12.8.4用partition() 實現“重排數組,讓奇數位於偶數前面”. . . . 553

12.8.5用lower_bound() 查找IP位址所屬的城市. . . . . . . . . . . . . 554

第4部分附錄

附錄A談一談網路編程學習經驗561

附錄B從《C++ Primer(第4版)》入手學習C++ 579

附錄C關於Boost 的看法591

附錄D關於TCP 並發連線的幾個思考題與試驗593

參考文獻599

作者介紹

陳碩,北京師範大學碩士,擅長C++ 多執行緒網路編程和實時分散式系統架構。曾在摩根史坦利IT 部門工作5 年,從事實時外匯交易系統開發。在美國加州矽谷某網際網路大公司工作,從事大規模分散式系統的可靠性工程。編寫了開源C++網路庫muduo,參與翻譯了《代碼大全(第2 版)》和《C++ 編程規範(繁體版)》,整理了《C++ Primer (第4 版)(評註版)》,並曾多次在各地技術大會演講。

相關詞條

熱門詞條

聯絡我們