笔记-线程安全的生命期管理

  • 当析构函数遇到多线程,当一个对象能被多个线程同时看到,那么对象的销毁时机就变得模糊不清了,可能出现多种竞争条件race condition:

    • 在即将析构一个对象时,如何得知此刻是  否有别的线程正在执行该对象的成员函数
    • 如何保证在执行成员函数期间,对象不会在另一个线程被析构
    • 在调用某个对象的成员函数之前,如何得知这个对象还活着? 它的析构函数不会碰巧执行到一半?
    • 记住share_ptr的用法.
  • 线程安全:三个条件.  多个线程同时访问时,其表现出正确的行为;无论os如何调度这些线程,无论这些线程的执行顺序如何交织;调用端代码无须额外的同步或其他协调动作.    那么c++,标准库中的大多数class都不是线程安全的,包括std::string,vector,map,必须加深能够额外的锁才可以供多个线程同时访问.
  • MutexLock/MutexLockGuard,自己实现的类.   MutexLock,利用RAII收方封装互斥器的常见与销毁/临界区在windows上是struct CRITICAL_SECTION,是可重入的,而linux上的pthread_mutex_t默认是不可重入的. MutexLock一般是别的class的数据成员.;;;;;;;;MutexLockGuard封装临界区的进入和退出,即加锁和解锁.MutexLockGuard一般是栈上对象,作用域刚好等于临界区.
  • 怎么样分析线程安全呢? 每个对象有自己的mutex_,因此不同对象之间不构成锁争用.  mutex_ 成员是mutable的,意味着const成员函数如Counter::value也能直接使用non-const的mutex_.
class Counter : boost::noncopyable{
    public:
    Counter():value_(0){}
    int value() const;
    int getAndIncrease();
    private:
        int value_;
        mutable MutexLock mutex_;
};
int Counter::value() const{
    MutexLockGuard lock(mutex_);///lock的析构会晚育返回对象的构造

    return value_;
    ///lock会在这里析构,作用域结束的时候,因此可以有效包括这个功效数据
}
int Counter::getAndIncrease(){
    MutexLockGuard lock(mutex_);
    int  ret  = value_++;///每个对象有自己的mutex_,因此不同对象之间不构成锁争用.
    return ret;
}
  • c++可能出现的内存有一下几个方面:
    1. 缓冲区溢出 buffer overrun
    2. 空悬指针/野指针
    3. 重复释放 double delete
    4. 内存泄露 memkory leak
    5. 不配对的new[]/delete
    6. 内存碎片 memory

正确使用智能指针share_ptr/weak_ptr解决前面的5个问题,

    1. 缓冲区溢出,用std::vector<char>/std::string或自己编写buffer class管理缓冲区,自动记住缓冲区的长度,公国成员函数而不是裸指针来修改缓冲区.
    2. 空悬指针/野指针,使用share_ptr/weak_ptr
    3. 重复释放,利用scopted_ptr,只在对象析构的时候释放一次
    4. 内存泄露:利用scopted_ptr,利利用
  • 对象的创建,  要做到线程安全,唯一的要求就是在狗仔期间不要泄露this指针:

    • 不要在构造函数中注册任何回调
    • 也不要在构造函数中把this指针传递给跨线程的对象
    • 即便在构造函数最后一行也不行
时间: 2025-01-12 08:50:39

笔记-线程安全的生命期管理的相关文章

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

线程安全的对象生命期管理 解决对象构造的线程安全 当我们需要动态分配对象时( 懒加载 ), 如果在多个线程中运行这一部分代码,可能出现多次初始化的问题. 单例模式 c++ 11 之后static 变量的初始化是线程安全的.可以利用静态变量来实现单例模式,解决重复初始化的问题. std::call_once 个人感觉不够优美,要传递一个flag 来标识初始化情况 线程访问未初始化的资源 比如在Thread类中,std::thread被构造之后立即开始执行线程中函数,然而函数中访问的资源可能还没有被

面向服务开发中三层架构中事务单元的生命期管理

    经典的三层分层结构,控制层(Control),服务层(Service),持久层(Repository)应用广泛,在面向服务(SOA)的架构中,配合DI.IOC实现开放灵活的技术架构.     SOA中,Respository面向数据访问,提供访问数据库.文件.或其他业务接口提供持久能力.Service面向业务,提供访问业务功能的接口,使用领域模型描述业务需求,方便产品人员.需求人员和客户沟通理解业务流程.最后,Control面向业务流程整合,提供基于事务的需求实现.     事务,用需求

使用 JointCode.Shuttle 管理远程服务对象的生命期

JointCode.Shuttle 是一个用于进程内 AppDomain 间通信的服务架构(不支持跨进程). 一般情况下,在进行跨 AppDomain 调用时,大部分人选择使用运行时库默认提供的.基于 MarshalByrefObject 类继承的通信机制.代码也很简单,例如: 1 namespace JoitCode.Shuttle.SimpleSample 2 { 3 public class MyService : MarshalByRefObject 4 { 5 public void

Android百日程序: Fragment动态管理和生命期

之前写过Fragment使用的程序,Fragment可以静态,也可以动态载入内存中的,这一章进一步看看如何动态地更换Fragment和看看Fragment生命期都有什么函数. 本章利用响应菜单点击事件,轮流载入不同的Fragment,显示不同的界面,效果如下: 开始的是没有载入Fragmen为空白: 点击菜单的NEXT FRAGMENT VIEW,就进入下一个界面,载入两个: 继续点击显示Fragment 1: 继续点击,显示Fragment2: 然后就是循环了: 如此循环显示不同画面. 一 首

tomcat系列分析之生命周期管理初始化动作

tomcat中有很多组件,要对这些组件进行生命周期的管理非常困难,tomcat中采用的是抽象出一个生命周期管理接口,然后所有的组件都实现该接口,当父组件启动时,同事负责将子组件启动起来,从而完成整tomcat的初始.启动.结束等动作. 来看下tomcat启动的过程,首先构造Bootstrap类,调用其中的init方法,完成类加载器的初始化,方便后面加载类使用,然后调用其中的load方法,实际上tomcat真正的启动动作是由Catalina类完成的.而这其中在BootStrap中调用Catalin

Siemens PLM TeamCenter 9.1生命周期管理软件

Siemens PLM TeamCenter 9.1生命周期管理软件Teamcenter 在构建时充分考虑了可扩展性. 无论是需要小规模部署来支持单个站点的小型团队,还是拥有遍布全球的众多站点以及复杂供应链的大型企业,或者介于其间的任何公司,Teamcenter 灵活的体系架构都能满足您当前的业务需求,并能随着贵公司的增长而继续保持出色表现. 下载内容包括: Siemens PLM TeamCenter 9.1 32和64位 为多国语言版本 Disc3 和 Disc4安装包 Teamcenter

[原创]java WEB学习笔记28: 会话与状态管理Cookie 机制

1.会话与状态管理 1)背景 ① HTTP协议是一种无状态的协议,WEB服务器本身不能识别出哪些请求是同一个浏览器发出的 ,浏览器的每一次请求都是完全孤立的: ② 作为 web 服务器,必须能够采用一种机制来唯一地标识一个用户,同时记录该用户的状态: ③ 问题:怎么才能实现网上商店中的购物车呢:某个用户从网站的登录页面登入后,再进入购物页面购物时,负责处理购物请求的服务器程序必须知道处理上一次请求的程序所得到的用户信息. 2)会话和会话状态 ① WEB应用中的会话:指一个客户端浏览器与WEB服务

Java实现生命周期管理机制

先扯再说 最近一直在研究某个国产开源的MySQL数据库中间件,拉下其最新版的代码到eclipse后,启动起来,然后做各种测试和代码追踪:用完想要关闭它时,拉出它的STOP类想要运行时,发现这个类里赫然只写以下几行代码,于是我感觉瞬间受到了很多伤害. public static void main(String[] args) { System.out.println(new Date() + ",server shutdown!"); } 这个中间件启动和运行的时候,开启了监听,启动着

CComBSTR的生命期

CComBSTR会自动管理字符串的内存空间,在析构时释放空间.由于C++对象在出其作用域时会进行析构.所以有一些情形下,使用CComBSTR容易犯下错误.来看以下代码: BSTR bstr1 = CComBSTR(L"hello"); BSTR bstr2 = CComBSTR(L"world"); TRACE(L"%s, %s\n", bstr1, bstr2); 本来可能预期输出的hello, world而实际输出是world, world