• 多线程下类对象的服务承诺探讨


    (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

    引言:

    多线程下,哪些需要类本身处理资源共享冲突,哪些需要类调用方保证共享冲突。
    类对象调用者 各自应该有哪些服务承诺?
    下面来探讨探讨。

    问题:

    当我们new一个类对象Object后,该对象存入一个指针中pObject;
    该pObject类对象指针的服务承诺有哪些。

    我们设计类的时候,可能碰到:

    1. 可能会遗忘对外承诺的服务连贯性;
    2. 有时也可能是过渡设计–过渡承诺自己完不成的任务;

    问题是:

    1. 如何区分哪些是类中应该承诺完成的?
    2. 如何区分哪些是应由外部调用者来承诺的?

    服务承诺

    我觉的外部调用者需要承诺的比较好定义,除了这部分外,是需要类中应该承诺的。
    当然这个也不是绝对的,从通常意义上来总结。

    外部调用者来说:

    1. 类对象指针pObject的维护肯定有外部负责维护的,pObject的声明周期应由外部来维护;
      pOjbect指针生命周期通常由外部主动维护,什么时候创建,什么时候销毁;
    2. 类对象构造,析构的完整性、唯一性应该由外部来维护;
      不能在类对象构造还未完成时,来使用pObject;
      不能在类对象析构调用中或析构后,还在使用pObject;
      不能调用类对象构造多次/或析构多次,这个应由外部保证;
      不能构造函数和析构函数在不同线程同时调用,应由外部保证;
      也即同一时刻,构造函数执行 与 类其它函数互斥,析构函数执行 与 类其它函数互斥;
    3. 类中的某函数要求执行的唯一性时,同构造析构函数一样,也由外部来维护其唯一性;
      例如某个函数要求调用时,和其它函数均互斥,这种类型和构造析构函数类似,可以由外部来保证其执行的唯一性。

    类对象对外的承诺:

    1. 除构造函数、析构函数外,其它函数的调用可重入性
      同一个函数,在不同线程上调用的可重入性需要类对象来保证
    2. 除构造函数、析构函数外,其它函数的调用的资源互斥
      不同函数,在不同线程上调用对资源访问的互斥,应由类对象来保证
    3. 除构造函数、析构函数外,其它函数的调用的互斥
      在不同的线程上调用,函数调用互斥应有类对象自己通过加锁等方式支持。
    4. 除构造函数、析构函数外,其它函数的调用的顺序性
      不同函数可能存在顺序调用关系,需要类对象通过自身加锁状态等方式来组织判断,不出现崩溃异常。

    典型例子

    有时也可以为了处理方便,把外部使用锁也放在类对象的内部:
    例如:
    下面这个类对外提供一个外部锁,供外部做某个外部时序处理时使用;

    class X
    {
    public:
        //  获取id
        uin32_t Get(); 
        // 保存
        void Store(info *);
        // 获取外部锁
        std::mutex* OuterMutex() {return &outer_mutex;}
    private:
       std::mutex inner_mutex;
       std::mutex outer_mutex;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    假如Store与Get本身都通过inner_mutex支持多线程访问;
    但部分情况,我们有外部要求,需要Get调用和Store能够一起做单线程访问约束;

     lock();
        {Get(); Store(info);} 
     unlock();
    
    • 1
    • 2
    • 3

    此时我们就可以通过外部锁来实现:在每个调用Get & Store的时候,使用外部锁加锁,当调用完毕Store后,释放外部锁。

       x.OuterMutex().lock();
        {
          uint32_t m = x.Get();
          ...
          x.Store(&myinfo);
        }
        x.OuterMutex().unlock();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这种对于类的部分函数绑定在一起的单线程访问约束项,就可以由外部调用函数,通过外部锁来实现。
    这样不会影响这些函数单独访问时的多线程支撑,Store在不和Get一起时,互相都可以多线程访问。

    (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

  • 相关阅读:
    【100个 Unity实用技能】| Unity将本地图片文件显示到Image组件中 通用方法整理
    黑客(网络安全)技术自学30天
    Java异常学习
    前端H5动态背景登录页面(下)
    【C++】list 容器最全详解(什么是list? list容器的常用接口有那些?)
    《opencv学习笔记》-- 非线性滤波:中值滤波、双边滤波
    MATLAB(6)GUI应用介绍
    synchronized 关键字和 volatile 关键字有什么区别?
    [数据集][目标检测][数据集][目标检测]智能手机检测数据集VOC格式5447张
    剑指 Offer 09. 用两个栈实现队列
  • 原文地址:https://blog.csdn.net/chunyexiyu/article/details/126043767