【Linux】设计模式

2023-11-06

目录

1设计模式

1.1概念

1.2设计模式分类

1.3单例模式

1.4单例模式代码演示

1.4.1懒汉模式

1.4.2饿汉模式

2.读写锁

2.1概念

2.2加锁规则

2.3接口

2.3.1初始化接口

2.3.2销毁接口

2.3.3解锁接口

2.3.4以读模式打开加锁

2.3.5以写模式加锁

3.自旋锁

4.乐观锁和悲观锁


1设计模式

1.1概念

        设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

1.2设计模式分类

        创建型模式:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

例如:工厂模式,单例模式

        结构型模式:这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

例如:适配器模式,桥接模式

        行为型模式:这些设计模式特别关注对象之间的通信。

例如:命令模式,观察者模式

1.3单例模式

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

1.4单例模式代码演示

1.4.1懒汉模式

///懒汉模式    
#include<iostream>    
#include<pthread.h>    
using namespace std;    
    
class Sigleton{    
  private:    
    Sigleton(){};    
    static Sigleton* st;    
    static pthread_mutex_t g_lock;    
    
  public:    
    static Sigleton* SinFun();    
    
    
};    
    
    
    pthread_mutex_t Sigleton::g_lock;    
    Sigleton* Sigleton::st=NULL;    
     Sigleton* Sigleton::SinFun(){    
       if(st==NULL){    
                                                                                                                                                         
       pthread_mutex_lock(&Sigleton::g_lock);    
       if(st==NULL){    
         st=new Sigleton;    
       }    
       pthread_mutex_unlock(&Sigleton::g_lock);    
       }    
       return st;    
    }    

   int main(){
      Sigleton* st=Sigleton::SinFun(); 
      Sigleton* st1=Sigleton::SinFun();
      if(st==st1){
        cout<<"st == st1"<<endl;
      }
      return 0;
    }  

1.4.2饿汉模式

#include<iostream>    
    
using namespace std;    
    
                                                                                                                                                         
class Sigleton{    
  private:    
    Sigleton(){    
    
    }    
    static Sigleton* st;    
public:    
    static Sigleton* GetInstance();    
    void Print(){    
      cout<<"程序启动就创建对象"<<endl;    
    }    
};             
                                                                                           
                                                          
Sigleton* Sigleton::st =new Sigleton;       
Sigleton* Sigleton::GetInstance(){    
  return st;                                         
}                                       
                                 
                                            
int main(){    
    Sigleton* st=Sigleton::GetInstance();                              
    st->Print();                                                     
    return 0;    
}      

2.读写锁

2.1概念

        读写锁是对互斥锁的升级版,适用于大量读少量写的情况。它提供了比互斥锁更好的并行性。因为以读模式加锁后,当有其他线程试图以读模式加锁时,并不会造成这些线程阻塞,但是读写锁更加复杂,开销更大。

        读写锁的三种状态:(1)以读模式加锁的状态 (2)以写模式加锁的状态(相当于互斥锁) (3)不加锁的状态

2.2加锁规则

               一次只有一个线程可以占用写模式的读写锁,一个执行流在进行写的时候,其他执行流既不能写,也不能读,只能陷入阻塞状态。

               多个读取线程可以同时占用读模式下的读写锁,在读写锁的内部有一个引用计数器,这个计数器记录着当前有多少线程以读模式加锁。每当一个线程以读模式打开读写锁的时候,引用计数器+1,当一个线程释放以读模式打开的读写锁的时候,引用计数器-1

        作用:判断释放读模式打开的读写锁时,能否完全解锁

        如果引用计数器完全减为0,表示当前没有读模式的线程占用读写锁,那么以读模式的读写锁就解锁了,引用计数器大于0,表明还有线程以读模式打开读写锁,就会和想要以写模式打开的读写锁进行互斥。

2.3接口

2.3.1初始化接口

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
参数   pthread_rwlock_t :读写锁类型
       rwlock:读写锁对象
       attr:属性值

2.3.2销毁接口

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数     rwlock:传递的互斥锁对象

2.3.3解锁接口

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
参数   rwlock:传递的互斥锁对象

2.3.4以读模式打开加锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);     //阻塞
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);  //非阻塞

参数  rwlock:传递的互斥锁对象

2.3.5以写模式加锁

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); //非阻塞接口
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);     //阻塞接口

参数   rwlock:传递的读写锁对象

3.自旋锁

自旋锁(busy-waiting类型)和互斥锁(sleep-waiting类型)的区别:


1.自旋锁加锁时,加不到锁,线程不会切换(时间片没有到的情况,时间片到了,也会线程切换),类似于while循环拿锁,会持续的尝试拿锁,直到拿到自旋锁


2.互斥锁加锁时,加不到锁,线程会切换(时间片没有到,也会切换),进入睡眠状态,当其他线程释放互斥锁(解锁)之后,被唤醒。在切换回来,进行抢锁。


3.白旋锁的优点:因为白旋锁不会引起调用者睡眠,所以自旋锁的效率远高于互斥锁


4.自旋锁的缺点:

        自旋锁一直占用着CPU,他在未获得锁的情况下,一直运行(自旋),所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低


5.适用于临界区代码较短时(直白的说:临界区代码执行时间短)的情况,使用自旋锁效率比较高。因为线程不用来回切换。


6.当临界区当中执行时间较长,自旋锁就不适用了,因为拿不到锁会占用CPU一直抢占锁。

4.乐观锁和悲观锁

            悲观锁:在线程访问临界区修改数据时,都会认为有其它线程并行修改情况发生,所以在线程修改数据之前就进行加锁,让多个线程互斥访问。常见的悲观锁有:互斥锁,读写锁,自旋锁等等。

        乐观锁:在线程访问临界区修改数据时,乐观的认为只有该线程在修改,大概率不会存在并行的情况。所以修改数据不加锁,但是在修改完毕后,进行判断,例如版本号控制,CAS无所编程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux】设计模式 的相关文章

随机推荐

  • 设计模式的口诀

    创建 结构 行为 1 抽工单建原 2 桥代理组装适配器的享元外观 3 访问者的策略备忘录 观察模板的迭代状态 命令中介者解释责任链
  • 最大子列和问题(四种方法 !!!终极版本)

    题目 给定K个整数组成的序列 N1 N 2 N K 连续子列 被定义为 Ni N i 1 Nj 其中 1 i j K 最大子列和 则被定义为所有连续子列元素的和中最大者 例如给定序列 2 11 4 13 5 2 其连续子列 11 4 13
  • Unity 优化1

    我认为unity的优化可以从三方面入手 分别是资源优化 性能优化和内存优化 由于每一方面的优化内容都比较多 我在这里主要分析一下性能优化 系统性能的好与差主要是通过系统的相应时间来衡量的 如果系统的响应时间超过500毫秒 用户就会感觉到明显
  • ASAP标注软件安装教程Ubuntu20.04

    以下转载自Github 需要针对ubuntu20 04 python3 8进行修改 DeepLearningCamelyon ASAP installation Ubuntu 16 04 at master 3dimaging DeepLe
  • 神武跑环遇到服务器维护,神武跑环不再痛苦:任务链重点难点详解攻略

    神武跑环不再痛苦 任务链重点难点详解攻略 大家快来看看吧 神武跑环不再痛苦 任务链重点难点详解攻略 相关新闻 任务链攻略 任务内容包括 找人 找到NPC对话即可 无时限 击败NPC 击败指定NPC即可 40分钟 难度较高 寻找物品交予NPC
  • kali功能介绍及安装(超详细)

    kali功能介绍及安装 超详细 一 kali简介 1 描述 Kali Linux是一个操作系统 2013 03 13诞生 基于Debian Linux的发行版 基于包含了约600个安全工具 省去了繁琐的安装 编译 配置 更新步骤 为所有工具
  • Python字符串中的特殊字符

    f 字符串 格式化字符串 在字符串前面加上 f 可以创建一个格式化字符串 在其中可以使用花括号 来插入变量或表达式的值 这种字符串会在运行时进行格式化处理 例如 name Alice age 25 print f My name is na
  • js实现图片懒加载原理

    有时候一个网页会包含很多的图片 例如淘宝京东这些购物网站 商品图片多只之又多 页面图片多 加载的图片就多 服务器压力就会很大 不仅影响渲染速度还会浪费带宽 比如一个1M大小的图片 并发情况下 达到1000并发 即同时有1000个人访问 就会
  • 学习记录Linux搭建nginx

    安装编译工具及库文件 yum y install make zlib zlib devel gcc c libtool openssl openssl devel 首先要安装 PCRE 下载 PCRE 安装包 下载地址 http downl
  • Pycharm常用快捷键大全

    版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net momoda118 article details 120155611 工欲善其事必先
  • 如何将任意大小的图片填充成一个方形

    这种方式我认为是最适合的图片预处理方式 随意resize会改变图片的特征 而进行填充的方式除了会改变原来标签的坐标以外 可以完全保留图片上所有的物体最原始的特征 def pad to square img pad value c h w i
  • 用Gerrit commit时报错missing Change-Id in message footer

    本人在第一次使用Gerrit时提交代码一直报change Id找不到 在git log的时候显示如下 查询其他文档发现是commit msg文件不存在导致的 现给出解决方案 提示错误 错误信息如下 remote Resolving delt
  • ctfshow终极考核wp

    文章目录 web640 web641 web642 web643 web644 web645 web646 web647 web648 web649 web650 web651 web652 web653 web654 web640 打开页
  • 【华为OD机试】支持优先级的队列【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 实现一个支持优先级的队列 高优先级先出队列 同优先级时先进先出 如果两个输入数据和优先级都相同 则后一个数据不入队列被丢弃 队列存储的数据内容是一个整数 输入描述 一
  • 修改 Linux VM 中单个用户最大进程数的限制

    在部署有并发任务执行的虚机上 会遇到 SSH 无法访问的问题 本文将帮助你找出其中一种比较特殊的原因 并提供解决方案 Note 以下案例分析基于 CentOS 7 对于其他版本的 Linux 操作系统 会略有不同 请注意 症状描述 虚机在正
  • BaoStock:一个免费、开源的python证券数据接口包

    如果需要获取历史行情数据 www baostock com是个很好的免费 开源的Python证券数据接口包 特点 使用方便 免费免费免费 返回的绝大部分的数据格式都是pandas DataFrame类型 入门代码如下 import baos
  • 分布式系统常用的模式

    分布式系统常用的模式 Ambassador 名称 大使 模式 介绍 作为应用程序和其他服务的 中间人 负责应用程序和其他服务之间的通信 包括日志 监控或重试处理等任务 举例 K8S使用Envoy作为一个 大使 来简化服务之间的通信 优点 降
  • MySQL多表查询

    目录 一 查询和新增结合 二 聚合查询 1 聚合函数 2 group by子句 三 联合查询 1 笛卡尔积 1 内连接 2 外连接 1 左外连接 2 右外连接 3 自连接 4 子查询 嵌套查询 5 合并查询 一 查询和新增结合 将表2中的数
  • 第十二届蓝桥杯省赛第二场C/C++大学B组编程题题目及解析

    目录 试题F 特殊年份 试题G 小平方 试题H 完全平方数 试题I 负载平衡 试题J 国际象棋 试题F 特殊年份 include
  • 【Linux】设计模式

    目录 1设计模式 1 1概念 1 2设计模式分类 1 3单例模式 1 4单例模式代码演示 1 4 1懒汉模式 1 4 2饿汉模式 2 读写锁 2 1概念 2 2加锁规则 2 3接口 2 3 1初始化接口 2 3 2销毁接口 2 3 3解锁接