logo资料库

linux多线程服务器端编程.pdf

第1页 / 共151页
第2页 / 共151页
第3页 / 共151页
第4页 / 共151页
第5页 / 共151页
第6页 / 共151页
第7页 / 共151页
第8页 / 共151页
资料共151页,剩余部分请下载后查看
Linux 多线程服务端编程 使用 muduo C++ 网络库 陈硕 (giantchen@gmail.com) 最后更新 2012-09-30 示范在多核时代采用现代 C++ 编写 多线程 TCP 网络服务器的正规做法 封面文案 内容简介 本书主要讲述采用现代 C++ 在 x86-64 Linux 上编写多线程 TCP 网络服务程序的 主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即 one loop per thread。这是在 Linux 下以 native 语言编写用户态高性能网络程序最成熟的模 式,掌握之后可顺利地开发各类常见的服务端网络应用程序。本书以 muduo 网络库 为例,讲解这种编程模型的使用方法及注意事项。 本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步 的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种多线程网 络编程模型就足以应对日常开发任务,编写运行于公司内网环境的分布式服务系统。 作者简介 陈硕,北京师范大学硕士,擅长 C++ 多线程网络编程和实时分布式系统架构。 曾在摩根士丹利 IT 部门工作 5 年,从事实时外汇交易系统开发。现在在美国加州硅 谷某互联网大公司工作,从事大规模分布式系统的可靠性工程。编写了开源 C++ 网 络库 muduo,参与翻译了《代码大全(第 2 版)》和《C++ 编程规范(繁体版)》,整 理了《C++ Primer (第 4 版)(评注版)》,并曾多次在各地技术大会演讲。 电子工业出版社
封底文案 看完了 W. Richard Stevens 的传世经典《UNIX 网络编程》,能照着例子用 Sockets API 编 写 echo 服务,却仍然对稍微复杂一点的网络编程任务感到无从下手?学习网络编程有哪些好 的练手项目?书中示例代码把业务逻辑和 Sockets 调用混在一起,似乎不利于将来扩展?网络 编程中遇到一些具体问题该怎么办?例如: • 程序在本机测试正常,放到网络上运行就 经常出现数据收不全的情况? • TCP 协议真的有所谓的“粘包问题”吗? 该如何设计消息帧的协议?又该如何编码 实现分包才不会掉到陷阱里? • 带外数据(OOB)、信号驱动 IO 这些高级 • 要处理成千上万的并发连接,似乎《UNIX 网 络 编 程》 介 绍 的 传 统 fork() 模 型 应 付不过来, 该用哪种并发模型呢?试试 select(2)/poll(2)/epoll(4) 这 种 IO 复 用模型吧,又感觉非阻塞 IO 陷阱重重,怎 么程序的 CPU 使用率一直是 100%? 特性到底有没有用? • 网络消息格式该怎么设计?发送 C struct 会有对齐方面的问题吗?对方不用 C/C++ 怎么通信?将来服务端软件升级,需要在 消息中增加一个字段,现有的客户端就必 须强制升级? • 要不改用现成的 libevent 网络库吧,怎么 查询一下数据库就把其他连接上的请求给 耽误了? • 再用个线程池吧。万一发回响应的时候对 方已经断开连接了怎么办?会不会串话? 读过《UNIX 环境高级编程》,想用多线程来发挥多核 CPU 的性能潜力,但对程序该用哪 种多线程模型感到一头雾水?有没有值得推荐的适用面广的多线程 IO 模型?互斥器、条件变 量、读写锁、信号量这些底层同步原语哪些该用哪些不该用?有没有更高级的同步设施能简化 开发?《UNIX 网络编程(第 2 卷)》介绍的那些琳琅满目的进程间通信(IPC)机制到底用哪 个才能兼顾开发效率与可伸缩性? 网络编程和多线程编程的基础打得差不多,开始实际做项目了,更多问题扑面而来: • 网上听人说服务端开发要做到 7 24 运 行,为了防止内存碎片连动态内存分配都 不能用,那岂不是连 C++ STL 也一并禁用 了?硬件的可靠性高到值得去这么做吗? • 传闻服务端开发主要通过日志来查错,那 么日志里该写些什么?日志是写给谁看的? 怎样写日志才不会影响性能? • 分布式系统跟单机多进程到底有什么本质 区别?心跳协议为什么是必需的,该如何 实现? • C++ 的大型工程该如何管理?库的接口如 何设计才能保证升级的时候不破坏二进制 兼容性?有没有更适合大规模分布式系统 的部署方案? 这本《Linux 多线程服务端编程:使用 muduo C++ 网络库》中,作者凭借多年的工程实 践经验试图解答以上疑问。当然,内容还远不止这些……
前言 本书主要讲述采用现代 C++ 在 x86-64 Linux 上编写多线程 TCP 网络服务程序的 主流常规技术,这也是我对过去 5 年编写生产环境下的多线程服务端程序的经验总 结。本书重点讲解多线程网络服务器的一种 IO 模型,即 one loop per thread。这是一 种适应性较强的模型,也是 Linux 下以 native 语言编写用户态高性能网络程序最成 熟的模式,掌握之后可顺利地开发各类常见的服务端网络应用程序。本书以 muduo 网络库为例,讲解这种编程模型的使用方法及注意事项。 muduo 是一个基于非阻塞 IO 和事件驱动的现代 C++ 网络库,原生支持 one loop per thread 这种 IO 模型。muduo 适合开发 Linux 下的面向业务的多线程服务 端网络应用程序,其中“面向业务的网络编程”的定义见附录 A。“现代 C++”指的 不是 C++11 新标准,而是 2005 年 TR1 发布之后的 C++ 语言和库。与传统 C++ 相比, 现代 C++ 的变化主要有两方面:资源管理(见第 1 章)与事件回调(见第 449 页)。 本书不是多线程编程教程,也不是网络编程教程,更不是 C++ 教程。读者应该 已经大致读过《UNIX 环境高级编程》、《UNIX 网络编程》、《C++ Primer》或与之内 容相近的书籍。本书不谈 C++11,因为目前(2012 年)主流的 Linux 服务端发行版的 g++ 版本都还停留在 4.4,C++11 进入实用尚需一段时日。 本书适用的硬件环境是主流 x86-64 服务器,多路多核 CPU、几十 GB 内存、千 兆以太网互联。除了第 5 章讲诊断日志之外,本书不涉及文件 IO。 本书分为四大部分,第 1 部分“C++ 多线程系统编程”考察多线程下的对象生 命期管理、线程同步方法、多线程与 C++ 的结合、高效的多线程日志等。第 2 部 分“muduo 网络库”介绍使用现成的非阻塞网络库编写网络应用程序的方法,以及 muduo 的设计与实现。第 3 部分“工程实践经验谈”介绍分布式系统的工程化开发 方法和 C++ 在工程实践中的功能特性取舍。第 4 部分“附录”分享网络编程和 C++ 语言的学习经验。 本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步 的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种多线程网 络编程模型就足以应对日常开发任务,编写运行于公司内网环境的分布式服务系统。 (本书不涉及分布式存储系统,也不涉及 UDP。) iii
iv 术语与排版范例 前言 本书大量使用英文术语,甚至有少量英文引文。设计模式的名字一律用英文, 例如 Observer、Reactor、Singleton。在中文术语不够突出时,也会使用英文,例 如 class、heap、event loop、STL algorithm 等。 注意几个中文 C++ 术语: 对象 实体(instance)、函数重载决议(resolution)、模板具现化(instantiation)、覆写 (override)虚函数、提领(dereference)指针。本书中的英语可数名词一般不用复数 形式,例如两个 class,6 个 syscall;但有时会用 (s) 强调中文名词是复数。fd 是文件 描述符(file descriptor)的缩写。“CPU 数目”一般指的是核(core)的数目。容量 单位 kB、MB、GB 表示的字节数分别为 103、106、109,在特别强调准确数值时,会 分别用 KiB、MiB、GiB 表示 210、220、230 字节。用诸如 §11.5 表示本书第 11.5 节, L42 表示上下文中出现的第 42 行代码。[JCP]、[CC2e] 等是参考文献,见书末清单。 一般术语用普通罗马字体,如 mutex、socket;C++ 关键字用无衬线字体,如 class、this、mutable;函数名和 class 名用等宽字体,如 fork(2)、muduo::EventLoop, 其中 fork(2) 表示系统函数 fork() 的文档位于 manpage 第 2 节,可以通过 man 2 fork 命令查看。如果函数名或类名过长,可能会折行,行末有连字号“-”,如 EventLoop- ThreadPool。文件路径和 URL 采用窄字体,例如 muduo/base/Date.h、http://chenshuo.com。 用中文楷体表示引述别人的话。 代码 本书的示例代码以开源项目的形式发布在 GitHub 上,地址是 http://github.com/ chenshuo/recipes/ 和 http://github.com/chenshuo/muduo/。本书配套页面提供全部源代码打包 下载,正文中出现的类似 recipes/thread 的路径是压缩包内的相对路径,读者不难找到 其对应的 GitHub URL。本书引用代码的形式如下,左侧数字是文件的行号,右侧的 “muduo/base/Types.h”是文件路径 1。例如下面这几行代码是 muduo::string 的 typedef。 muduo/base/Types.h 15 namespace muduo 16 { 17 18 #ifdef MUDUO_STD_STRING 19 using std::string; 20 #else // !MUDUO_STD_STRING 21 typedef __gnu_cxx::__sso_string string; 22 #endif muduo/base/Types.h 1 在第 6、7 两章的 muduo 示例代码中,路径 muduo/examples/XXX 会简写为 examples/XXX。此外,第 8 章会 把 recipes/reactor/XXX 简写为 reactor/XXX。 Linux 多线程服务端编程:使用 muduo C++ 网络库 (excerpt) http://www.chenshuo.com/book/
前言 v 本书假定读者熟悉 diff -u 命令的输出格式,用于表示代码的改动。 本书正文中出现的代码有时为了照顾排版而略有改写,例如改变缩进规则,去掉 单行条件语句前后的花括号等。就编程风格而论,应以电子版代码为准。 联系方式 邮箱:giantchen@gmail.com 主页:http://chenshuo.com/book (正文和脚注中出现的 URL 可从这里找到。) 微博:http://weibo.com/giantchen 博客:http://blog.csdn.net/Solstice 代码:http://github.com/chenshuo 陈硕 中国·香港 Linux 多线程服务端编程:使用 muduo C++ 网络库 (excerpt) http://www.chenshuo.com/book/
内容一览 第 1 部分 C++ 多线程系统编程 . . . . . . . 第 1 章 线程安全的对象生命期管理 . . 第 2 章 线程同步精要 . . 第 3 章 多线程服务器的适用场合与常用编程模型 . 第 4 章 C++ 多线程系统编程精要 . 第 5 章 高效的多线程日志 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 第 2 部分 muduo 网络库 第 6 章 muduo 网络库简介 . . 第 7 章 muduo 编程示例 . . 第 8 章 muduo 网络库设计与实现 . . . . . . . . . . . . . . . 第 3 部分 工程实践经验谈 . . . 第 9 章 分布式系统工程实践 . . 第 10 章 C++ 编译链接模型精要 . . 第 11 章 反思 C++ 面向对象与虚函数 . . 第 12 章 C++ 经验谈 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 第 4 部分 附录 . . . . . . . . . . . . . . . . . . . . . . 附录 A 谈一谈网络编程学习经验 . . 附录 B 从《C++ Primer(第 4 版)》入手学习 C++ . 附录 C 关于 Boost 的看法 . . . 附录 D 关于 TCP 并发连接的几个思考题与试验 . . 参考文献 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 31 59 83 . . . . . . . . . . . . . . . 107 123 . 125 . . . 177 . . 277 337 . 339 . 391 . 429 . 501 559 . 561 . 579 . 591 . 593 . 599 . . . . . . . . . . . . . . . . . . . . .
第 1 部分 C++ 多线程系统编程 第 1 章 线程安全的对象生命期管理 1.1 当析构函数遇到多线程 . . . 1.1.1 线程安全的定义 . . . MutexLock 与 MutexLockGuard . . 1.1.2 1.1.3 一个线程安全的 Counter 示例 . . . . . 1.2 对象的创建很简单 . . 1.3 销毁太难 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1 mutex 不是办法 . . . 1.3.2 作为数据成员的 mutex 不能保护析构 . . . . . . . . . . . . . . . . . . . . . . . 1.11.1 enable_shared_from_this . . 1.11.2 弱回调 . . . 1.12 替代方案 . . . . 1.13 心得与小结 . . . 1.14 Observer 之谬 . . . 1.4 线程安全的 Observer 有多难 . . 1.5 原始指针有何不妥 . . . . 1.6 神器 shared_ptr/weak_ptr . . . 1.7 插曲:系统地避免各种指针错误 . 1.8 应用到 Observer 上 . . . 1.9 再论 shared_ptr 的线程安全 . . 1.10 shared_ptr 技术与陷阱 . . . . 1.11 对象池 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 目录 1 3 3 4 4 4 5 7 7 8 8 11 13 14 16 17 19 21 . 23 . 24 . 26 . 26 . 28 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 第 2 章 线程同步精要 2.1 互斥器(mutex) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 . 32 vii
viii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 只使用非递归的 mutex . 2.1.2 死锁 . . . . . . 2.2 条件变量(condition variable) . . 2.3 不要用读写锁和信号量 . . . . 2.4 封装 MutexLock、MutexLockGuard、Condition . 2.5 线程安全的 Singleton 实现 . . . . . . . 2.6 2.7 归纳与总结 . . . . 2.8 借 shared_ptr 实现 copy-on-write . . . sleep(3) 不是同步原语 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 3.3.2 线程池 . . . 3.3.3 推荐模式 . . 第 3 章 多线程服务器的适用场合与常用编程模型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6 “多线程服务器的适用场合”例释与答疑 . . 3.1 进程与线程 . . 3.2 单线程服务器的常用编程模型 . 3.3 多线程服务器的常用编程模型 . one loop per thread . . . . . . . . . . . 3.5.1 必须用单线程的场合 . . 3.5.2 单线程程序的优缺点 . . 3.5.3 适用多线程程序的场景 . . . . . 3.4 进程间通信只用 TCP . . 3.5 多线程服务器的适用场合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 第 4 章 C++ 多线程系统编程精要 . . . . . . . . . . 4.1 基本线程原语的选用 . . 4.2 C/C++ 系统库的线程安全性 . 4.3 Linux 上的线程标识 . . . 4.4 线程的创建与销毁的守则 . . . . . . . . . . . pthread_cancel 与 C++ . . exit(3) 在 C++ 中不是线程安全的 . . . . 4.5 善用 __thread 关键字 . 4.6 多线程与 IO . . . . . . . . . . . . . . . . . 4.4.1 4.4.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 目录 . 33 . 35 . 40 . 43 . 44 . 48 . 50 . 51 . 52 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 . 59 61 . . 62 . 62 . 63 . 64 65 67 69 70 71 74 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 . . 84 . . 85 . 89 . . 91 . . . 94 94 . . 96 . . . . 98 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Linux 多线程服务端编程:使用 muduo C++ 网络库 (excerpt) http://www.chenshuo.com/book/
分享到:
收藏