初探《Linux多线程服务端编程 使用muduo C++网络库》

第1部分 c++多线程系统编程

第1章 线程安全的对象生命期管理

1. 多个线程同时看到一个对象时,析构可能出现race condition
2. 线程安全的类的定义:多个线程同事访问时,其表现出正确的行为;无论操作系统如何调度这些线程,无论这些线程的执行顺序如何交织;调用端代码无须额外的同步或其他协调动作。
3. MutexLock封装临界区,用RAII手法封装互斥器的创建和销毁。临界区在linux下是pthread_mutex_t,默认是不可重入的。
4. class noncopyable的基本思想是把构造函数和析构函数设置protected权限,这样子类可以调用,但是外面的类不能调用,那么当子类需要定义构造函数的时候不至于通不过编译。但是最关键的是noncopyable把复制构造函数和复制赋值函数做成了private,这就意味着除非子类定义自己的copy构造和赋值函数,否则在子类没有定义的情况下,外面的调用者是不能够通过赋值和copy构造等手段来产生一个新的子类对象的
5. 对象创建避免race condition:不要在构造函数中注册任何回调;不要在构造函数中把this指针传递跨线程的对象;即便在构造函数的最后一行也不行。
6. 作为数据成员的mutex不能 保护析构
7. 同时读写一个class的两个对象,有潜在的死锁的可能。
8. 尝试创建线程安全的observer:采用对象池
9. 原始指针析构对象可能造成悬空指针
10. 使用智能指针share_ptr和weak_ptr可以解决直到对象是否还活着的问题
11. 系统地避免各种指针错误:采用智能指针可以避免缓冲区溢出、悬空指针、野指针、重复释放、内存泄露、不配对new/delete。内存碎片需要别的思路
12. shared_ptr的线程安全级别和内建类型和string一样:一个shared_ptr对象实体可以被多个线程同时读取;两个shared_ptr对象实体可以被两个线程同时写入,析构算写操作;如果要从多个线程读写同一个shared_ptr对象,那么需要加锁。
13. shared_ptr会意外延长对象的生命周期。
14. shared_ptr拷贝开销比原始指针要高。可以采用pass by const reference
15. ???析构动作在创建时被捕获:析构函数不再是必须的;share_ptr可以持有任何对象,而且能安全地释放;share_ptr对象可以安全地跨越模块边界,比如从DLL里返回,而不会造成从模块A分配内存在模块B里被释放这种错误。;二进制兼容性:即便foo对象的大小变了,那么旧的客户代码仍然可以使用新的动态库,而无需重新编译;析构函数可以定制。
16. 析构所在线程:可能析构所在的线程不是同一个线程,而如果析构时间较长可能阻塞主线程
17. 现成的RAII handle:资源获取即初始化:配置资源动作同时将获得的资源交给handle对象如share_ptr
18. 对象池:
19. 弱回调
20. 多线程编程的建议:用流水线,生产者消费者,任务队列这些有规律的机制,最低限度的共享数据。

第2章线程同步精要

1. 并发编程两种基本模型:message passing和shared memory。
2. 线程同步的四项基本原则:
    最低限度地共享对象,减少需要同步的场合。
    使用高级的并发构件如:TaskQueue、Producer-Consumer Queue、CountDownLatch
    使用底层同步原语,只用非递归的互斥器和条件变量,慎用读写锁,不要用信号量
    除了使用atomic整数外,不要自己编写lock-free代码,也不要使用“内核级”同步原语。
3. 互斥器: 用RAII手法封装mutex的创建、销毁、加锁、解锁这四个操作;只用非递归的mutex(即不可重入的mutex);不受用调用lock()和unlock()函数,一切交给栈上的Guard对象的构造和析构函数负责。在每次构造Guard对象的时候,思考一路上(调用栈上)已经持有的锁,防止因加锁顺序不同而导致死锁。
4. 

第3章多线程服务器的适用场合与常用编程模型

1. 进程比喻为人:每个人都有自己的记忆,人与人通过谈话(消息传递)来交流,谈话既可以是面谈(同一台服务器),也可以在电话里谈(不同服务器,有网络通信)。面谈和电话谈的区别在于,面谈可以立即直到对方是否死了(crash,sigchld), 而电话谈只能通过周期性的心跳来判断对方是否还活着。
2. 容错(万一有人突然死了);扩容(新人中途加进来了);负载均衡(把甲的活挪给乙做);退休(甲要修复bug,先别派新任务,等他做完手上的事情就把他重启)
3. 线程的特点是共享地址空间,从而可以高校地共享数据,在单核时代,多线程没有多大价值。
4. 应用最广泛的单线程编程模型:非阻塞IO + IO多路复用模型,即Reactor模式。
5. 多线程编程模型推荐:non-blocking IO + one loop per thread模式
6. one loop per thread模式:线程数目基本固定,可以在程序启动的时候设置,不会频繁创建与销毁;可以很方便地在线程间调配负载;IO事件发生的线程是固定的,同一个TCP连接不必考虑事件并发。
7. 对于没有IO而光有计算任务的线程,使用event loop有点浪费,可以使用blocking queue 实现任务队列taskQueue
8. 推荐模式:one(event) loop per thread + thread pool:event loop用作IO复用,配合非阻塞IO和定时器;thread pool用来做计算,具体可以是任务队列或生产者消费者队列
9. 进程间通信首选TCP,没错不论是否在同一台主机上;
10. TCP这种字节流方式通信,会有marshal/unmarshal的开销,需要我们选择合适的消息格式,可以选google的protocol buffers
11. 分布式系统中TCP的长连接通信?
12. 必须使用单线程的场合:程序可能会fork;限制程序的CPU占用率(例子看门狗进程)
13. Event loop是非抢占的,容易造成优先级反转
14. 多线程使用场景:提高响应速度、让IO和“计算”相互重叠,降低latency。
15.  

C++多线程系统编程精要

1. 

你可能感兴趣的:(网络编程)