当前位置: 首页 > news >正文

《shared_ptr源码剖析》

【shared_ptr导读】上一节,我们为大家介绍了unique_ptr的底层原理和实现。相对于unique_ptr,shared_ptr也是被大家广泛使用的智能指针,shared_ptr内部的原理是怎样的?shared_ptr是多线程安全的吗?

图片     

   本文将以Centos标准库为基础,剖析shared_ptr的源码,shared_ptr主要包含两个部分:shared_ptr_base.h和shared_ptr.h,虽然涉及的文件不多,但为了实现一套完备的内存托管方案出来,gcc还是设计很多类出来。且看如下图片,笔者将结合图片逐步为您剖析shared_ptr托管内存的原理和细节。

图片

1. shared_ptr结构和源码     

     我们直接使用的shared_ptr定义在shared_ptr.h文件中,shared_ptr仅仅只是定义了些接口给我们使用,该类本身并没有执行任何操作,具体的内存管理以及引用计数相关的还需要关注它的父类__shared_ptr,shared_ptr定义如下:

template<typename _Tp>class shared_ptr : public __shared_ptr<_Tp>{    public:      constexpr shared_ptr() noexcept          :__shared_ptr<_Tp>() { }      shared_ptr(const shared_ptr&) noexcept = default;            template<typename _Tp1>       explicit shared_ptr(_Tp1* __p)         : __shared_ptr<_Tp>(__p) { }           template<typename _Tp1, typename _Deleter>      shared_ptr(_Tp1* __p, _Deleter __d)        : __shared_ptr<_Tp>(__p, __d) { }           template<typename _Deleter>      shared_ptr(nullptr_t __p, _Deleter __d)        : __shared_ptr<_Tp>(__p, __d) { }            ......};

2. __shared_ptr结构和源码   

     __shared_ptr内部维护了一个__shared_count类型的成员,__shared_count顾名思义就是托管内存被引用的计数,当__shared_ptr执行拷贝构造或者拷贝赋值时,__shared_count内部将对其内部维护的引用计数执行++操作。

template<typename _Tp, _Lock_policy _Lp>class __shared_ptr{public:   typedef _Tp   element_type;   constexpr __shared_ptr() noexcept   : _M_ptr(0), _M_refcount(){ }   template<typename _Tp1>   explicit __shared_ptr(_Tp1* __p)      : _M_ptr(__p), _M_refcount(__p)   {       __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)       static_assert(sizeof(_Tp1) > 0, "incomplete type" );       __enable_shared_from_this_helper(_M_refcount, __p, __p);   }      template<typename _Tp1, typename _Deleter>    __shared_ptr(_Tp1* __p, _Deleter __d)     : _M_ptr(__p), _M_refcount(__p, __d)   {     __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)     __enable_shared_from_this_helper(_M_refcount, __p, __p);   }      template<typename _Tp1>   __shared_ptr& operator=(const __shared_ptr<_Tp1, _Lp>& __r)           noexcept   {      _M_ptr = __r._M_ptr;      _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw      return *this;   }         ......     private:  ......  _Tp*    _M_ptr;  // Contained pointer.  __shared_count<_Lp>  _M_refcount; //Reference counter.}; 

3. __shared_count的源码和结构     

      __shared_count其实是个类,从名字可知,__shared_count也是和托管内存引用计数相关的类,__shared_count类内部维护了_Sp_counted_base类型的成员指针_M_pi,_M_pi又指向_Sp_counted_base派生类对象_Sp_counted_ptr的地址。

template<_Lock_policy _Lp>class __shared_count{template<typename _Ptr>explicit __shared_count(_Ptr __p) : _M_pi(0){   __try   {       _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);   }   __catch(...){        delete __p;        __throw_exception_again;   }}......private:  friend class __weak_count<_Lp>;  _Sp_counted_base<_Lp>*  _M_pi; }

  _Sp_counted_ptr类型内部持有托管内存的指针_M_ptr, 这样_M_pi内部就既可以控制引用计数,又可以在最后释放托管内存_M_ptr。_Sp_counted_ptr的结构很简单。

template<typename _Ptr, _Lock_policy _Lp>class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>{ public:  explicit _Sp_counted_ptr(_Ptr __p)    : _M_ptr(__p) { }  virtual void _M_dispose() noexcept  { delete _M_ptr; }  virtual void _M_destroy() noexcept  { delete this; }  virtual void* _M_get_deleter(const std::type_info&)  { return 0; }  _Sp_counted_ptr(const _Sp_counted_ptr&) = delete;  _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete; protected:   _Ptr      _M_ptr;  // copy constructor must not throw};

     _Sp_counted_base便是shared_ptr托管内存的核心,内存释放与否与它维护的引用计数_M_use_count、_M_weak_count相关。那为啥有两个引用计数?难道shared_ptr内部维护两份不同的内存?

template<_Lock_policy _Lp = __default_lock_policy>class _Sp_counted_base : public _Mutex_base<_Lp>{public:     _Sp_counted_base() noexcept   :_M_use_count(1), _M_weak_count(1)   { }         virtual ~_Sp_counted_base() noexcept   { }     virtual void _M_dispose() noexcept = 0;         virtual void _M_destroy() noexcept   {       delete this;   }   virtual void* _M_get_deleter(const std::type_info&) = 0;   void _M_add_ref_copy()   {       //引用计数额递增,都是调GNU C++ 库的接口,保证引用计数原子化递增       __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1);    }   void _M_add_ref_lock();   void _M_release() noexcept   {    _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)    {      /*      使用 GNU C++库中的__exchange_and_add_dispatch函数      将_M_use_count的值减去1,并将原来的值与1进行比较。      如果比较结果为真,即原来的值为1,那么表明原来的值为1,      并且现在已经将其减为0。     */      _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);            /*_M_use_coun减为0时便调用_M_dispose()接口释放托管的内存        _M_ptr,而_M_ptr是由派生类_Sp_counted_ptr进行管理。        进而内存释放操作由_Sp_counted_ptr类负责,        当前类的_M_dispose()仅仅是个纯虚接口。       */            /*释托管内存的操作并非线程安全的。        gcc标准库仅仅保证了托管内引用计数的线程安全      */      _M_dispose();            if (_Mutex_base<_Lp>::_S_need_barriers)      {         _GLIBCXX_READ_MEM_BARRIER;         _GLIBCXX_WRITE_MEM_BARRIER;      }     /*      使用 GNU C++库中的__exchange_and_add_dispatch函数      将_M_weak_count的值减去1,并将原来的值与1进行比较。      如果比较结果为真,即原来的值为1,那么表明原来的值为1,      并且现在已经将其减为0。    */      _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);      if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)      {         _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);         /*           释放内存时,并没有进行任何的加锁保护,           也说明了一点shared_ptr托管的内存在多线程的环境下是非线程安全的         */         _M_destroy();      }    }  }   void _M_weak_add_ref() noexcept   {        __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1);    }    void _M_weak_release() noexcept   {       _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)       {          _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);          if (_Mutex_base<_Lp>::_S_need_barriers)          {             _GLIBCXX_READ_MEM_BARRIER;             _GLIBCXX_WRITE_MEM_BARRIER;          }          _M_destroy();       }   }   long _M_get_use_count() const noexcept   {      return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);   }private:     _Sp_counted_base(_Sp_counted_base const&) = delete;   _Sp_counted_base& operator=(_Sp_counted_base const&) = delete;   _Atomic_word  _M_use_count;   _Atomic_word  _M_weak_count;};

     _M_use_count表示托管对象的引用计数,控制托管对象的释放,当引用计数为0时,最终调用和托管内存相关的类_Sp_counted_ptr的接口_M_dispose()释放内存。__shared_ptr拷贝时,__shared_count也会随之进行拷贝,__shared_count的拷贝会最终转调_Sp_counted_base的接口_M_add_ref_copy()。

~__shared_count() noexcept{   if (_M_pi != nullptr)      _M_pi->_M_release();}__shared_count(const __shared_count& __r) noexcept  : _M_pi(__r._M_pi){    if (_M_pi != 0)_M_pi->_M_add_ref_copy();
}__shared_count& operator=(const __shared_count& __r) noexcept{_Sp_counted_base<_Lp>* __tmp = __r._M_pi;   if (__tmp != _M_pi){       if (__tmp != 0)          __tmp->_M_add_ref_copy();       if (_M_pi != 0)          _M_pi->_M_release();      _M_pi = __tmp;   }   return *this;
}

      _M_weak_count表示管理对象的引用计数,管理对象也是一块内存,这块内存是在初始化第一个shared_ptr时被申请出来的。

template<typename _Ptr>explicit __shared_count(_Ptr __p) : _M_pi(0)
{   __try   {       _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);   }   __catch(...){       delete __p;       __throw_exception_again;   }}

       _M_destroy释放内存时,也需要依赖_M_weak_count进行控制,weak_ptr内部其实持有的就是这个管理对象的指针,当weak_ptr拷贝时,管理对象的引用计数_M_weak_count就会增加,当_M_weak_count为0时,管理对象_M_pi就会析构且释放内存。那_M_weak_count是如何进行加减的? 

 4.__weak_count的源码和结构

template<_Lock_policy _Lp>class __weak_count{public:  constexpr __weak_count() noexcept : _M_pi(0)  {  }  __weak_count(const __shared_count<_Lp>& __r) noexcept      : _M_pi(__r._M_pi)   {       if (_M_pi != 0)         _M_pi->_M_weak_add_ref();   }      __weak_count(const __weak_count<_Lp>& __r) noexcept    : _M_pi(__r._M_pi)   {       //拷贝构造,增加引用计数       if (_M_pi != 0)         _M_pi->_M_weak_add_ref();   }   ~__weak_count() noexcept   {        /析构,释放引用计数        if (_M_pi != 0)          _M_pi->_M_weak_release();   }   __weak_count<_Lp>& operator=(const __shared_count<_Lp>& __r) noexcept   {        _Sp_counted_base<_Lp>* __tmp = __r._M_pi;        if (__tmp != 0)           __tmp->_M_weak_add_ref();        if (_M_pi != 0)            _M_pi->_M_weak_release();        _M_pi = __tmp;        return *this;   }       __weak_count<_Lp>& operator=(const __weak_count<_Lp>& __r) noexcept   {       _Sp_counted_base<_Lp>* __tmp = __r._M_pi;       if (__tmp != 0)          __tmp->_M_weak_add_ref();       if (_M_pi != 0)          _M_pi->_M_weak_release();        _M_pi = __tmp;        return *this;   }       void _M_swap(__weak_count<_Lp>& __r) noexcept    {        _Sp_counted_base<_Lp>* __tmp = __r._M_pi;        __r._M_pi = _M_pi;        _M_pi = __tmp;    }        long _M_get_use_count() const noexcept    {         return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0;     }        ......private:    friend class __shared_count<_Lp>;    _Sp_counted_base<_Lp>*  _M_pi;};

       由文章首页可以看到__shared_count、__weak_count共同持有同一个_Sp_counted_base类指针,而__weak_count是用于控制__weak_ptr的,当__weak_ptr进行拷贝析构时,__weak_count会做响应的加减。无论是增加引用计数_M_weak_add_ref,还是减少引用计数_M_weak_release,最终调用就是_Sp_counted_base类中的接口。

void _M_weak_add_ref() noexcept    __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }void _M_weak_release() noexcept{  _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);  if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1)                 == 1)  {     _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);     /判是否需要内存屏障     if (_Mutex_base<_Lp>::_S_need_barriers)     {       /如果需要就开启内存读、写屏障的操作,确保多线程环境下,        _GLIBCXX_READ_MEM_BARRIER;        _GLIBCXX_WRITE_MEM_BARRIER;      }      //确保释放当前管理类对象内存操作的安全性      _M_destroy();   }}virtual void _M_destroy() noexcept    delete this; }

   重点关注:引用计数_M_weak_count、_M_use_count始终由 _Sp_counted_base负责,托管对象内存由_Sp_counted_ptr负责,管理对象的内存(即由_M_weak_count控制的内存)由_Sp_counted_base负责。5. enable_shared_from_this      假如我们需要把当前类对象以shared_ptr包裹起来,返回给外部使用,那么可以将类继承自enable_shared_from_this,看了下enable_shared_from_this的源码,shared_from_this()接口只是将内部持有的weak_ptr转换成shared_ptr。

template<typename _Tp>class enable_shared_from_this{protected:  constexpr enable_shared_from_this() noexcept { }  enable_shared_from_this(const enable_shared_from_this&) noexcept { }  enable_shared_from_this&  operator=(const enable_shared_from_this&) noexcept  {      return *this;   }  ~enable_shared_from_this() { }public:  shared_ptr<_Tp> shared_from_this()  {      return shared_ptr<_Tp>(this->_M_weak_this);   }    shared_ptr<const _Tp> shared_from_this() const  {     return shared_ptr<const _Tp>(this->_M_weak_this);  }private:   ......   mutable weak_ptr<_Tp>  _M_weak_this;};

      shared_from_this()接口最后还是会转调到__shared_ptr类的拷贝构造函数,将托管的内存_M_ptr拷贝(浅拷贝),_M_refcount引用计数进行拷贝构造,将_M_use_count递增1。

template<typename _Tp1>explicit __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r)   : _M_refcount(__r._M_refcount) // may throw{   /*    *STL库类型检查,    *确保__weak_pt托管的对象类型能隐私转换成__shared_pt托管的对象类型。    */   __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)   _M_ptr = __r._M_ptr;}


  

相关文章:

《shared_ptr源码剖析》

【shared_ptr导读】上一节&#xff0c;我们为大家介绍了unique_ptr的底层原理和实现。相对于unique_ptr&#xff0c;shared_ptr也是被大家广泛使用的智能指针&#xff0c;shared_ptr内部的原理是怎样的&#xff1f;shared_ptr是多线程安全的吗&#xff1f; 本文将以Centos标准库…...

关于markdown实现页面跳转(调查测试:csdn(博客编写效果、发布效果)、typroa中md转pdf的使用情况)

一-方法介绍 [点击跳转到标题0](#1) <a href"#2">正文2</a>### <span id"2">标题0</span>二、跳转测试区 点击跳转到标题0 正文2 三、测试结果 场景MDspan-可标题写博客时候&#xff0c;右侧显示区效果可以发布博客的效果可以…...

入门级容器技术解析:Docker和K8s的区别与关系

目录 &#x1f3af;学习小目标&#xff1a; 关于容器 传统物理机&#x1f5a5;️ 虚拟机&#x1f4bb; 为什么使用容器技术呢&#xff1f;&#x1f914; 容器技术&#x1f943; Docker—容器化平台 K8s(Kubernetes)—容器编排系统​ Docker和K8s有什么关系和区别&#…...

《Rust权威指南》学习笔记(五)

高级特性 1.在Rust中&#xff0c;unsafe是一种允许绕过Rust的安全性保证的机制&#xff0c;用于执行一些Rust默认情况下不允许的操作。unsafe存在的原因是&#xff1a;unsafe 允许执行某些可能被 Rust 的安全性检查阻止的操作&#xff0c;从而可以进行性能优化&#xff0c;如手…...

数据库软考历年上午真题与答案解析(2018-2024)

本题考查计算机总线相关知识。 总线&#xff08;Bus&#xff09;是计算机各种功能部件之间传送信息的公共通信干线&#xff0c;它是由导线组成的传输线束。 根据总线连接设备范围的不同&#xff0c; 分为&#xff1a;1.片内总线&#xff1a;芯片内部的总线&#xff1b; 2.系统…...

HTML5 文件上传(File Upload)详解

HTML5 文件上传&#xff08;File Upload&#xff09;详解 HTML5 提供了强大的文件上传功能&#xff0c;允许用户通过网页选择文件并上传到服务器。以下是关于文件上传控件的详细说明。 1. 基本的文件上传控件 使用 <input> 标签的 type"file" 属性可以创建一…...

构建属于你的七牛云文件上传工具:Qiniu Uploader 详解(从 0 到 1 实现)

GitHub 仓库地址&#xff1a;https://github.com/hahala2333/qiniu-upload &#x1f4da; 简介 在现代 Web 开发中&#xff0c;静态资源的上传和管理是不可避免的需求。为了简化将本地资源上传到七牛云存储的过程&#xff0c;我们构建了 Qiniu Uploader 工具。它具备灵活的配置…...

Spring Boot 项目中集成 Kafka-03

在 Spring Boot 项目中集成 Kafka 有多种方式&#xff0c;适应不同的应用场景和需求。以下将详细介绍几种常用的集成方法&#xff0c;包括&#xff1a; 使用 Spring Kafka (KafkaTemplate 和 KafkaListener)使用 Spring Cloud Stream 与 Kafka Binder使用 Spring for Apache K…...

如何在2025年创建一个网站:使用US Domain Center和WordPress的终极指南

在本指南中&#xff0c;我们将向你展示如何正确地使用US Domain Center和WordPress创建一个网站。无论你是要启动一个个人博客&#xff0c;还是一个在线商店&#xff0c;我们都会提供简单易懂的步骤指导。无需技术技能 — — 只需按照我们的简单步骤操作&#xff0c;你就能在今…...

LLM 训练中存储哪些矩阵:权重矩阵,梯度矩阵,优化器状态

LLM 训练中存储哪些矩阵 目录 LLM 训练中存储哪些矩阵深度学习中梯度和优化器是什么在 LLM 训练中通常会存储以下矩阵: 权重矩阵:这是模型的核心组成部分。例如在基于 Transformer 架构的 LLM 中,每一层的多头注意力机制和前馈神经网络都会有相应的权重矩阵。以 BERT 模型为…...

【JVM】总结篇之对象内存布局 执行引擎

文章目录 对象内存布局对象的实例化对象的内存布局对象的方问定位 执行引擎 对象内存布局 对象的实例化 new对象流程&#xff1f;&#xff08;龙湖地产&#xff09; 对象创建方法&#xff0c;对象的内存分配。&#xff08;360安全&#xff09; 1.判断对象对应的类是否加载、链…...

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型 目录 机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型1 过拟合和欠拟合1.1 过拟合1.2 欠拟合 2 正则化惩罚2.1 概念2.2 函数2.3 正则化种类 3 K折交叉验证3.1 概念3.2 图片理解3.3 函数导入3.4 参数理解 4 训练模型K折交…...

【图像处理】OpenCv + Python 实现 Photoshop 中的色彩平衡功能

前言 这是使用 python 和 OpenCv 实现的 Photoshop 中色彩平衡功能的代码&#xff0c;可以设置阴影&#xff0c;高光和中间调的色调参数来调整图片的色彩平衡。 参考文章二也有 python 版本的代码实现&#xff0c;虽然中间调的部分貌似没有实现&#xff0c;但是理论部分讲解还…...

基于vue框架的的校园快递管理系统x0xm0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,校园跑腿,快递代取,代取进度,评价信息 开题报告内容 基于Vue框架的校园快递管理系统开题报告 一、研究背景与意义 随着电子商务的蓬勃发展&#xff0c;校园快递业务急剧增长&#xff0c;成为校园生活中不可或缺的一部分。然而&a…...

【Vim Masterclass 笔记05】第 4 章:Vim 的帮助系统与同步练习(L14+L15+L16)

文章目录 Section 4&#xff1a;The Vim Help System&#xff08;Vim 帮助系统&#xff09;S04L14 Getting Help1 打开帮助系统2 退出帮助系统3 查看具体命令的帮助文档4 查看帮助文档中的主题5 帮助文档间的上翻、下翻6 关于 linewise7 查看光标所在术语名词的帮助文档8 关于退…...

智能体(Agent)如何具备自我决策能力的机理与实现方法

一、智能体自我决策能力的机理 从人工智能和控制理论的角度看&#xff0c;智能体能够“自我决策”的核心在于其 “感知–认知–行动” 的循环过程&#xff0c;以及在此过程中引入自主学习与自主优化的机制。经过优化与补充&#xff0c;智能体具备自我决策能力的机理可以分解为…...

Redis 数据库源码分析

Redis 数据库源码分析 我们都知道Redis是一个 <key,value> 的键值数据库&#xff0c;其实也就是一个 Map。如果让我来实现这样一个 Map&#xff0c;我肯定是用数组&#xff0c;当一个 key 来的时候&#xff0c;首先进行 hash 运算&#xff0c;接着对数据的 length 取余&…...

vue3 css实现文字输出带光标显示,文字输出完毕,光标消失的效果

Vue实现过程如下&#xff1a; <template><div ><p ref"dom_element" class"typing" :class"{over_fill: record_input_over}"></p></div> </template> <script setup> import {onMounted, ref} from…...

【Leetcode】731. 我的日程安排表 II

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 实现一个程序来存放你的日程安排。如果要添加的时间内不会导致三重预订时&#xff0c;则可以存储这个新的日程安排。 当三个日程安排有一些时间上的交叉时&#xff08;例如三个日程…...

浅谈棋牌游戏开发流程四:核心业务逻辑(二)——房间匹配与对局流程

一、前言&#xff1a;让玩家轻松坐上“牌桌” 在上一篇文章中&#xff0c;我们深入探讨了用户系统与登录流程&#xff0c;了解了如何让“陌生人”转变为游戏中的“正式玩家”。接下来&#xff0c;我们将迈向游戏的核心环节——房间匹配与对局流程。这是玩家实际参与游戏、互动…...

大学生HTML5期末作业 Web前端网页制作 html5+css3+js html+css网页设计 美食 美食模版2个页面

大学生HTML5期末作业 Web前端网页制作 html5css3js htmlcss网页设计 美食 美食模版2个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修…...

Java100道面试题

1.JVM内存结构 1. 方法区&#xff08;Method Area&#xff09; 方法区是JVM内存结构的一部分&#xff0c;用于存放类的相关信息&#xff0c;包括&#xff1a; 类的结构&#xff08;字段、方法、常量池等&#xff09;。字段和方法的描述&#xff0c;如名称、类型、访问修饰符…...

MySQL 日志简介

总览 MySQL Server 有以下⼏种⽇志&#xff0c;可以记录服务器正在发⽣的活动。 ⽇志类型⽇志信息 ⼀般查询⽇志 (General query log) 已建⽴的客⼾端连接和从客⼾端接收到的语句 错误⽇志 (Error log) mysqld在启动、运⾏或停⽌时遇到的问题 慢查询⽇志 (Slow query log) 执⾏…...

ubuntu清理磁盘

ubuntu清理磁盘脚本&#xff1a; #&#xff01;/bin/bash#shell脚本用#作注释行,但是第一行的#&#xff01;/bin/bash例外sudo apt-get clean sudo rm -rf /tmp/* sudo rm -rf /var/cache/*cd /var/log/ sudo du -h -d 1 rm -rf ./*cd ~/.cache sudo du -h -d 1 rm -rf ./*apt…...

鸿蒙APP之从开发到发布的一点心得

引言&#xff1a; 做鸿蒙开发大概有1年左右时间了&#xff0c;从最开始的看官方文档、看B站视频&#xff0c;到后来成功发布两款个人APP&#xff08;房贷计算极简版、时简时钟 轻喷&#xff0c;谢谢&#xff09;。简单描述一下里边遇到的坑以及一些经历吧。 学习鸿蒙开发 个…...

C++二十三种设计模式之享元模式

C二十三种设计模式之享元模式 一、组成二、特点三、目的四、缺点五、示例代码 一、组成 抽象享元类&#xff1a;声明操作方法。 具体享元类&#xff1a;使用内部数据和外部数据来实现操作方法。 享元管理者类&#xff1a;创建和管理具体享元对象。 二、特点 1、创建享元对象…...

基于Python的音乐播放器 毕业设计-附源码73733

摘 要 本项目基于Python开发了一款简单而功能强大的音乐播放器。通过该音乐播放器&#xff0c;用户可以轻松管理自己的音乐库&#xff0c;播放喜爱的音乐&#xff0c;并享受音乐带来的愉悦体验。 首先&#xff0c;我们使用Python语言结合相关库开发了这款音乐播放器。利用Tkin…...

基于32单片机的智能语音家居

一、主要功能介绍 以STM32F103C8T6单片机为控制核心&#xff0c;设计一款智能远程家电控制系统&#xff0c;该系统能实现如下功能&#xff1a; 1、可通过语音命令控制照明灯、空调、加热器、窗户及窗帘的开关&#xff1b; 2、可通过手机显示和控制照明灯、空调、窗户及窗帘的开…...

【C语言程序设计——入门】C语言入门与基础语法(头歌实践教学平台习题)【合集】

目录&#x1f60b; ​​​​​​ ⚙️C语言环境配置&#xff1a;Windows配置C语言环境(超级详细) <第1关&#xff1a;程序改错> 任务描述 相关知识 1. 头文件的引用 2. 基本语法规则 编程要求 测试说明 通关代码 测试结果 <第2关&#xff1a;scanf 函数>…...

基于Springboot的知名作家交流系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业多年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…...

服务器数据恢复—离线盘数超过热备盘数导致raidz阵列崩溃的数据恢复

服务器数据恢复环境&故障&#xff1a; 一台配有32块硬盘的服务器在运行过程中突然崩溃不可用。经过初步检测&#xff0c;基本上确定服务器硬件不存在物理故障。管理员重启服务器后问题依旧。需要恢复该服务器中的数据。 服务器数据恢复环境&#xff1a; 1、将服务器中硬盘…...

conda安装及demo:SadTalker实现图片+音频生成高质量视频

1.安装conda 下载各个版本地址&#xff1a;https://repo.anaconda.com/archive/ win10版本&#xff1a; Anaconda3-2023.03-1-Windows-x86_64 linux版本&#xff1a; Anaconda3-2023.03-1-Linux-x86_64 Windows安装 环境变量 conda -V2.配置conda镜像源 安装pip conda…...

内蒙古水系详细很全shp格式arcgis软件无偏移坐标下载后内容测评

标题中的“内蒙古水系详细很全shp格式arcgis软件无偏移坐标”指的是一个地理信息系统&#xff08;GIS&#xff09;数据集&#xff0c;该数据集详细记录了内蒙古地区的水系信息&#xff0c;并以ESRI公司的标准矢量数据格式——Shapefile&#xff08;.shp&#xff09;进行存储。S…...

RK3588平台开发系列讲解(系统篇)Linux Kconfig的语法

文章目录 一、什么是Kconfig二、config模块三、menuconfig四、menu 和 endmenu五、choice 和 endchoice六、source七、depends on八、default九、help十、逻辑表达式沉淀、分享、成长,让自己和他人都能有所收获!😄 一、什么是Kconfig Kconfig的语法及代码结构非常简单。本博…...

c#使用SevenZipSharp实现压缩文件和目录

封装了一个类&#xff0c;方便使用SevenZipSharp&#xff0c;支持加入进度显示事件。 双重加密压缩工具范例&#xff1a; using SevenZip; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.…...

【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 1. 二叉排序树的基本概念 2. 二叉排序树节点结构体定义 3. 创建二叉排序树 4. 判断是否为二叉排序树 5. 递归查找关键字为 6 的结点并输出查找路径 6. 删除二叉排序树中的节点 测试说明 通关代码 测试结果 任务描述 本关任务&a…...

C# 服务生命周期:Singleton、Scoped、Transient

文章目录 1、概念:服务生命周期单例 (Singleton) :作用域 (Scoped) :瞬态 (Transient) : 2、对 Scoped 和 Transient 进一步辨析Scoped 生命周期Transient 生命周期选择哪种生命周期 1、概念:服务生命周期 单例 (Singleton) : 整个应用程序生命周期中只有一个实例被创建并共享…...

如何让用户在网页中填写PDF表格?

在网页中让用户直接填写PDF表格&#xff0c;可以大大简化填写、打印、扫描和提交表单的流程。通过使用复选框、按钮和列表等交互元素&#xff0c;PDF表格不仅让填写过程更高效&#xff0c;还能方便地在电脑或移动设备上访问和提交数据。 以下是在浏览器中显示可填写PDF表单的四…...

w140体育馆使用预约平台的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…...

Linux(Ubuntu)下ESP-IDF下载与安装完整流程(4)

接前一篇文章:Linux(Ubuntu)下ESP-IDF下载与安装完整流程(3) 本文主要看参考官网说明,如下: 快速入门 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 Linux 和 macOS 平台工具链的标准设置 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 前边几回讲解了第一步 —— …...

PDF预览插件

PDF预览插件 可用于当前页面弹窗形式查看,可增加一些自定义功能 pdf预览插件 代码块: pdfobject.js <div class="pdfwrap"><div class="item"><h3>笑场</h3><div class="tags"><p>李诞</p><i&…...

【微服务】2、网关

Spring Cloud微服务网关技术介绍 单体项目拆分微服务后的问题 服务地址问题&#xff1a;单体项目端口固定&#xff08;如黑马商城为8080&#xff09;&#xff0c;拆分微服务后端口各异&#xff08;如购物车808、商品8081、支付8086等&#xff09;且可能变化&#xff0c;前端难…...

计算机网络--路由表的更新

一、方法 【计算机网络习题-RIP路由表更新-哔哩哔哩】 二、举个例子 例1 例2...

网络安全抓包

#知识点&#xff1a; 1、抓包技术应用意义 //有些应用或者目标是看不到的&#xff0c;这时候就要进行抓包 2、抓包技术应用对象 //app,小程序 3、抓包技术应用协议 //http&#xff0c;socket 4、抓包技术应用支持 5、封包技术应用意义 总结点&#xff1a;学会不同对象采用…...

字玩FontPlayer开发笔记8 Tauri2文件系统

字玩FontPlayer开发笔记8 Tauri2文件系统 字玩FontPlayer是笔者开源的一款字体设计工具&#xff0c;使用Vue3 ElementUI开发&#xff0c;源代码&#xff1a; github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer 笔记 字玩目…...

http源码分析

一、HttpURLConnection http连接池源码分析 二、HttpClient 连接池&#xff0c;每个路由最大连接数 三、OkHttp okhttp的连接池与socket连接...

【vim】vim常用操作总结

vim常用操作总结 一&#xff0c;简介二&#xff0c;操作介绍2.1 命令模式2.1.1 删除&#xff08;剪切&#xff09;光标所在行2.1.2 复制2.1.3 粘贴2.1.4 跳到行末2.1.5 跳到行首2.1.6 撤销操作 2.2 视图模式2.3 命令模式2.4 编辑模式 三&#xff0c;总结 一&#xff0c;简介 在…...

【学Rust开发CAD】1 环境搭建

文章目录 一、搭建C/C编译环境二、安装Rust三、配置 PATH 环境变量四、验证安装结果五、安装编辑工具 一、搭建C/C编译环境 Rust 的编译工具依赖 C 语言的编译工具&#xff0c;这意味着你的电脑上至少已经存在一个 C 语言的编译环境。如果你使用的是 Linux 系统&#xff0c;往…...

RK3588开发笔记-spi接口调试

目录 前言 一、SPI接口简介 二、原理图连接 三、设备树配置 四、spi调试 五、spi应用软件接口 总结 前言 在嵌入式系统开发中,SPI(Serial Peripheral Interface)接口作为一种同步、全双工、多设备、多主机的通信协议,广泛应用于连接各种外围设备,如ADC、DAC、数据存…...

AlphaPi相关硬件驱动提取

初涉硬件编程&#xff0c;在咸鱼上搞了几块AlphaPi和microbit的板鼓捣了一下&#xff0c;alphapi生态不完善&#xff0c;网上又无任何文档&#xff0c;搞封闭&#xff0c;可玩性实在有限&#xff0c;但貌似相关扩展板是可以插microbit的&#xff0c;于是想把这些扩展版用microb…...