muduo库学习笔记1-C++多线程系统编程

  • 网上都说这本书很适合初学者入门学习, 我今天开始准备从头再来;

第一章线程安全的对象管理

  • 对象的生与死不能由对象自身拥有的mutex(互斥器)来保护;
  • 如何避免对象析构时可能存在的race conditon(竞态条件)是C++多线程编程面临的基本问题, C++借用shared_ptr和weak_ptr完美解决;
  • shared_ptr和weak_ptr是实现线程安全的Observer设计模式的必备技术;
当析构函数遇到多线程
  • C++要求程序员自己管理对象的生命期, 这在多线程环境下显得尤为困难; 因为析构的时候会出现一些问题:

    • 在即将析构一个对象时, 怎么知道其他线程正在使用该对象的成员函数;
    • 如何保证我在使用一个对象的时候, 没有其他线程来析构这个对象;
    • 调用一个对象之前, 如何知道这个对象还活着, 它的析构函数会不会碰巧执行到一半?
      • 可以简单的通过shared_ptr进行一劳永逸的解决这些问题;
  • 什么是线程安全?
    • 一个线程安全的类(class)应当满足三个条件:

      • 多个线程同时访问时, 其表现出正确的行为;
      • 无论操作系统如何调度这些线程, 无论这些线程的执行顺序如何交织(interleaving);
      • 调用端的代码无需额外的同步或其他协调动作;
  • 锁的封装都可以进行临界区的处理(Critical section) -- 也就是把加锁放在构造函数, 把解锁放在析构函数, 这样就可以只加锁, 不管解锁就好了;
对象的创建很简单
  • 对此昂的构造要做到线程安全, 唯一的要求是在构造起见不要泄露this指针;

    • 不要在构造函数中注册任何回调;
    • 也不要在构造函数把this指针传给跨线程的对象;
    • 几遍在构造函数的最后一行也不行;
    • 如果this指针被泄漏给其他对象, 可能是一个半成品;
互斥变量的销毁太难
  • 因为析构函数中会把mutex销毁;
  • 作为成员的mutex不能保护析构
  • 一个函数如果要锁住相同类型的多个对象, 为了保证始终按相同的顺序加锁, 我们可以比较mutex对象的地址, 始终加锁地址较小的;
  • 对象的三种关系: composition(组合), aggregation(聚合), association(关联);
  • 解决空悬指针的办法是引入一层间接层, 更好的方法是使用引用计数;

神器shared_ptr/weak_ptr

  • shared_ptr是引用计数型智能指针;

    • 引用计数为0, 自动销毁;
  • weak_ptr也是一个引用计数型智能指针, 但它不增加对象的引用计数, 即弱引用(weak);
  • C++的内存问题大致有这么几个方面:
    • 缓冲区溢出(buffer overrun);
    • 空悬指针/野指针;
    • 重复释放(double delete);
    • 内存泄漏(memory leek);
    • 不配对的new[]/delete;
    • 内存碎片(memory fragmetation);
  • scoped_ptr/shared_ptr/weak_ptr都是值语意;
  • 多线程访问同一个shared_ptr, 正确的做法是用mutex保护;
  • shared_ptr技术与陷阱;
    • 意外延长水箱的生命周期: shared_ptr是强引用, 只要有一个指向x对象的shared_ptr存在, 该对象就不会析构;
    • shared_ptr拷贝开销比原始指针高;
    • 析构函数在创建时被捕获;
    • 现成的RAII handle, RAII(资源获取即初始化)是C++语言区别于其他所有编程语言的最重要的特性, 一个不懂RAII的C++程序员不是一个合格的C++程序员;
    • shared_ptr是管理共享资源的利器, 需要注意避免循环引用, 通常的做法是owner持有指向child的shared_ptr, child持有指向owner的weak_ptr;

对象池

  • 如果对象还活着, 就调用它的成员函数, 否则忽略它;
  • 用流水线, 生产者消费者, 任务队列这些有规律的机制, 最低限度地共享数据;

C++怎么实现线程安全的更多相关文章

  1. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  2. [高并发]Java高并发编程系列开山篇--线程实现

    Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...

  3. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  4. Java 线程

    线程:线程是进程的组成部分,一个进程可以拥有多个线程,而一个线程必须拥有一个父进程.线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不能拥有系统资源.它与父进程的其他线程共享该进程的所有资 ...

  5. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  6. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  7. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  8. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  9. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  10. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

随机推荐

  1. CSS3 利用border-radius实现椭圆角

    效果如图: border-radius共有8个属性值,有四个角,每个角对应两个值(分别是x轴和y轴的值). border-radius: 0 20% 20% 0/0 50% 50% 0; /的左右两边 ...

  2. Hadoop记录-Hadoop NameNode 高可用 (High Availability) 实现解析

    Hadoop NameNode 高可用 (High Availability) 实现解析   NameNode 高可用整体架构概述 在 Hadoop 1.0 时代,Hadoop 的两大核心组件 HDF ...

  3. BIO和NIO

    在了解BIO,NIO,AIO之前先了解一下IO的几个概念:   1.同步与异步 同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous com ...

  4. Windows环境手动DOS命令构建apk文件

    第一步 抽取资源id,生成R.java aapt p[ackage] -f [-A <assets>] -S <res> -M <AndroidManifest.xml& ...

  5. ios 不支持-,-时间。

    var date = "2000-08-29";  console.log(new Date(date).getTime());解决办法 date .replace(/-/g, ' ...

  6. ASP.NET Web API 2 使用 AuthorizationFilter(授权过滤器)实现 Basic 认证

    Ø  前言 在 Web 项目中授权认证方式有很多种,本文主要讲述基于 Basic 的认证方式.这是一种比较简单.常见的认证方式,主要是将请求的用户名和密码进行加密后返回给调用方,比较适合采用用户名.密 ...

  7. DevExpress 之 GridControl 自定义列

    Ø  前言 DevExpress 控件大家应该都有所了解,使用这个框架实现B/S或C/S的,都是非常出色的.本文主要讨论下 GridControl 中如何[自定义列]或[计算列],可使用以下两种方法实 ...

  8. 【BZOJ3697】采药人的路径 点分治

    [BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...

  9. oracle 远程连接不到dba用户

    如果要远程连接192.168.10.44上的oracle,那么192.168.10.44服务器必须启动TNSListener.(配置文件 listener.ora) http://www.111cn. ...

  10. Codeforces 1065F(树形dp)

    题目链接 题意 给一棵树,进行如下操作,如果当前点非叶子,则往子树移动,否则最多向上移动k次,问从根节点开始最多访问多少叶子 思路 预处理出每个点最多能“白嫖”到几个叶子,根据下一个点的状态更新最优方 ...