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

互联网大赛建设网站策划书河南网站建设报价

互联网大赛建设网站策划书,河南网站建设报价,建立个人网站能干,广东上海专业网站建设公司哪家好目录 线程安全的单例模式 什么是单例模式 单例模式的特点 饿汉实现方式和懒汉实现方式 饿汉⽅式实现单例模式 懒汉⽅式实现单例模式 懒汉⽅式实现单例模式(线程安全版本) 单例式线程池 ThreadPool.hpp threadpool.cc 运行结果 线程安全和重⼊问题 常⻅锁概念 死…

目录

线程安全的单例模式

什么是单例模式

单例模式的特点  

饿汉实现方式和懒汉实现方式

饿汉⽅式实现单例模式

懒汉⽅式实现单例模式

懒汉⽅式实现单例模式(线程安全版本)

单例式线程池

ThreadPool.hpp

threadpool.cc

运行结果

线程安全和重⼊问题

常⻅锁概念

死锁

死锁四个必要条件

避免死锁

破坏死锁的四个必要条件 

避免死锁算法

STL中的容器是否是线程安全的?

智能指针是否是线程安全的?

其他常⻅的各种锁


线程安全的单例模式

什么是单例模式

单例模式的特点  

某些类, 只应该具有⼀个对象(实例), 就称之为单例.

例如⼀个男⼈只能有⼀个媳妇. 在很多服务器开发场景中, 经常需要让服务器加载很多的数据(上百G) 到内存中. 此时往往要⽤⼀个单例的类来管理这些数据.

单例模式 分为饿汉模式懒汉模式

饿汉实现方式和懒汉实现方式

[洗碗的例⼦]

吃完饭, ⽴刻洗碗, 这种就是饿汉⽅式. 因为下⼀顿吃的时候可以⽴刻拿着碗就能吃饭.

吃完饭, 先把碗放下, 然后下⼀顿饭⽤到这个碗了再洗碗, 就是懒汉⽅式.

饿汉模式: 直接准备好

懒汉模式: 用时才准备,延时加载        例如: 写时拷贝 ,new malloc 中真实物理空间的加载

懒汉方式最核心的思想是 "延时加载". 从而能够优化服务器的启动速度.

饿汉⽅式实现单例模式

template <typename T>
class Singleton 
{static T data;
public:static T* GetInstance() {return &data;}
};

只要通过Singleton 这个包装类来使⽤ T 对象,则⼀个进程中只有⼀个T对象的实例.

懒汉⽅式实现单例模式

template <typename T>
class Singleton 
{static T* inst;
public:static T* GetInstance() {if (inst == NULL) {inst = new T();}return inst;}
};

存在⼀个严重的问题, 线程不安全.

第⼀次调⽤ GetInstance 的时候, 如果两个线程同时调⽤,可能会创建出两份 T 对象的实例.但是后续再次调⽤,就没有问题了.

懒汉⽅式实现单例模式(线程安全版本)

// 懒汉模式, 线程安全 
template <typename T>
class Singleton 
{volatile static T* inst; // 需要设置 volatile 关键字, 否则可能被编译器优化. static std::mutex lock;
public:static T* GetInstance() {if (inst == NULL) {    // 双重判定空指针, 降低锁冲突的概率, 提⾼性能. lock.lock(); // 使⽤互斥锁, 保证多线程情况下也只调⽤⼀次 new. if (inst == NULL) {inst = new T();}lock.unlock();}return inst;}
};

注意事项:

1. 加锁解锁的位置

2. 双重 if 判定,避免不必要的锁竞争

3. volatile关键字防⽌过度优化

单例式线程池

ThreadPool.hpp

#pragma once
#include <queue>
#include <iostream>
#include <string>
#include <vector> //用vector管理线程
#include <memory>
#include "log.hpp"
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"namespace ThreadPoolModule
{using namespace LockModule;using namespace ThreadModule;using namespace CondModule;using namespace LogModule;const static int defaultnum = 5;using thread_t = std::shared_ptr<Thread>;void Defaulttest(){while (true){LOG(LogLevel::INFO) << "test";sleep(1);}}template <typename T>class ThreadPool{private:bool IsEmpty(){return _taskq.empty();}// 执行任务void HandlerTask(std::string name){LOG(LogLevel::INFO)<<"线程"<< name <<"进入handlerTask";// 线程醒来就一直执行while (true){T t;{LockGuard lockguard(_mutex);while (IsEmpty() && _isrunning){_wait_num++;_cond.Wait(_mutex);_wait_num--;}// 任务队列为空 && 线程池退出了才退出    ,重要重要 if(IsEmpty() && !_isrunning)break;// 1.拿任务t = _taskq.front();_taskq.pop();}//在临界区外 ,处理任务 ,效率更高// 2.处理任务   规定传入的所有的任务, 必须提供()方法t(name);}LOG(LogLevel::INFO) << "线程: " << name << " 退出";}ThreadPool(const ThreadPool<T> &) = delete;//拷贝构造禁掉ThreadPool<T>& operator=(const ThreadPool<T> &) = delete;//赋值重载禁掉ThreadPool(int num = defaultnum) //构造函数设为私有: _num(num),_wait_num(0),_isrunning(false){// 创建num个线程for (int i = 0; i < num; i++){//bind  此时所有创建出来的线程,转而去执行HandlerTask_threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerTask, this,std::placeholders::_1 )));LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "成功";}}public:static ThreadPool<T> * getInstance() //单例模式{if(_instance == NULL){LockGuard lockguard(_mutex_singleton);if(_instance == NULL){LOG(LogLevel::INFO) << "单例首次被执行,需要加载对象...";_instance = new ThreadPool<T>();}}return _instance;}~ThreadPool(){}void Start(){if(_isrunning) return;_isrunning = true; // bug fix??for (auto &thread_ptr : _threads){thread_ptr->Start();LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << "成功";}}void Wait(){for (auto &thread_ptr : _threads){thread_ptr->Join();LOG(LogLevel::INFO) << "回收线程" << thread_ptr->Name() << "成功";}}//任务入队列void Enqueue(T &&in)//这个会被多线程调用 ,先加锁{//只要队列扛得住 ,就一直加LockGuard lockguard(_mutex);if(!_isrunning) return;_taskq.push(std::move(in));if(_wait_num > 0 ) _cond.Notify();}//退出线程池void Stop(){LockGuard lockguard(_mutex);if(_isrunning){// 3. 不能在入任务了_isrunning = false; // 不工作// 1. 让线程自己退出(要唤醒) && // 2. 历史的任务被处理完了if(_wait_num>0)_cond.NotifyAll();}}private:int _num;                       // 线程个数std::queue<T> _taskq;           // 任务队列  是临界资源std::vector<thread_t> _threads; // 管理线程 ,其中是线程的指针Mutex _mutex;Cond _cond;int _wait_num;bool _isrunning ;               //线程池的运行状态static ThreadPool<T>* _instance; //单例模式的静态指针static Mutex _mutex_singleton;//只用来保护单例};//静态方法初始化应放在类外template<typename T>ThreadPool<T> *ThreadPool<T>::_instance = NULL;template<typename T>Mutex ThreadPool<T>::_mutex_singleton; //只用来保护单例
}

threadpool.cc

#include"ThreadPool.hpp"
#include<memory>
#include"Task.hpp"
using namespace ThreadPoolModule;int main()
{ENABLE_CONSOLE_LOG();ThreadPool<task_t>::getInstance()->Start();char c;int cnt = 5;while (cnt){// std::cin >> c;ThreadPool<task_t>::getInstance()->Enqueue(Push);cnt--;sleep(1);}ThreadPool<task_t>::getInstance()->Stop();ThreadPool<task_t>::getInstance()->Wait();
}

运行结果

线程安全和重⼊问题

线程安全描述的是线程

重入描述的是函数

线程安全:

就是多个线程在访问共享资源时,能够正确地执⾏,不会相互⼲扰或破坏彼此的执⾏结果。⼀般⽽⾔,多个线程并发同⼀段只有局部变量的代码时,不会出现不同的结果。但是对全局变量或者静态变量进⾏操作,并且没有锁保护的情况下,容易出现该问题。

重⼊:

同⼀个函数被不同的执⾏流调⽤,当前⼀个流程还没有执⾏完,就有其他的执⾏流再次进⼊, 我们称之为重⼊。⼀个函数在重⼊的情况下,运⾏结果不会出现任何不同或者任何问题,则该函数被 称为可重⼊函数,否则,是不可重⼊函数。

重⼊其实可以分为两种情况

  • 多线程重⼊函数
  • 信号导致⼀个执⾏流重复进⼊函数

常⻅锁概念

死锁

  • 死锁是指在⼀组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源⽽处于的⼀种永久等待状态。
  • 为了方便表述,假设现在线程A,线程B必须同时持有锁1和锁2,才能进⾏后续资源的访问

申请⼀把锁是原⼦的,但是申请两把锁就不⼀定了

造成的结果是

死锁四个必要条件

  • 互斥条件:⼀个资源每次只能被⼀个执⾏流使用
  • 请求与保持条件:⼀个执⾏流因请求资源⽽阻塞时,对已获得的资源保持不放
  • 不剥夺条件:⼀个执⾏流已获得的资源,在末使⽤完之前,不能强⾏剥夺
  • 循环等待条件:若⼲执⾏流之间形成⼀种头尾相接的循环等待资源的关系

避免死锁

破坏死锁的四个必要条件 

破坏循环等待条件问题:资源⼀次性分配,使⽤超时机制、加锁顺序⼀致

// 下⾯的C++不写了,理解就可以 
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <unistd.h>
// 定义两个共享资源(整数变量)和两个互斥锁 
int shared_resource1 = 0;
int shared_resource2 = 0;
std::mutex mtx1, mtx2;// ⼀个函数,同时访问两个共享资源 
void access_shared_resources()
{// std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock);// std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock);// // 使⽤ std::lock 同时锁定两个互斥锁 // std::lock(lock1, lock2);// 现在两个互斥锁都已锁定,可以安全地访问共享资源 int cnt = 10000;while (cnt){++shared_resource1;++shared_resource2;cnt--;}// 当离开 access_shared_resources 的作⽤域时,lock1 和 lock2 的析构函数会被⾃动调⽤ // 这会导致它们各⾃的互斥量被⾃动解锁 
}// 模拟多线程同时访问共享资源的场景 
void simulate_concurrent_access()
{std::vector<std::thread> threads;// 创建多个线程来模拟并发访问 for (int i = 0; i < 10; ++i){threads.emplace_back(access_shared_resources);}// 等待所有线程完成 for (auto &thread : threads){thread.join();}// 输出共享资源的最终状态 std::cout << "Shared Resource 1: " << shared_resource1 << std::endl;std::cout << "Shared Resource 2: " << shared_resource2 << std::endl;
}int main()
{simulate_concurrent_access();return 0;
}
$ ./a.out // 不⼀次申请 
Shared Resource 1: 94416
Shared Resource 2: 94536$ ./a.out // ⼀次申请 
Shared Resource 1: 100000
Shared Resource 2: 100000

避免死锁算法

  • 死锁检测算法
  • 银⾏家算法

STL中的容器是否是线程安全的?

不安全.

原因是, STL 的设计初衷是将性能挖掘到极致, ⽽⼀旦涉及到加锁保证线程安全, 会对性能造成巨⼤的影响.  ⽽且对于不同的容器, 加锁⽅式的不同, 性能可能也不同(例如hash表的锁表和锁桶). 因此 STL 默认不是线程安全.

如果需要在多线程环境下使⽤, 往往需要调⽤者⾃⾏保证线程安全.

智能指针是否是线程安全的?

智能指针是安全的,指针指向的对象不一定.

对于 unique_ptr, 由于只是在当前代码块范围内⽣效, 因此不涉及线程安全问题.

对于 shared_ptr, 多个对象需要共⽤⼀个引⽤计数变量, 所以会存在线程安全问题. 但是标准库实现的时 候考虑到了这个问题, 基于原⼦操作(CAS)的⽅式保证 shared_ptr 能够⾼效, 原⼦的操作引⽤计数.

其他常⻅的各种锁

  • 悲观锁:在每次取数据时,总是担⼼数据会被其他线程修改,所以会在取数据前先加锁(读锁, 写锁,⾏锁等),当其他线程想要访问数据时,被阻塞挂起。
  • 乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新 数据前,会判断其他数据在更新前有没有对数据进⾏修改。主要采⽤两种⽅式:版本号机制和 CAS操作。
  • CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则⽤新值更 新。若不等则失败,失败则重试,⼀般是⼀个⾃旋的过程,即不断重试。
  • ⾃旋锁,读写锁.

http://www.dtcms.com/wzjs/33307.html

相关文章:

  • 石家庄官网设计及搭建浙江seo推广
  • 商城网站开发项目文档seo关键词排名优
  • 怎么把网站源码上传到空间根目录视频百度推广培训班
  • 天津建设安全协会网站郑州关键词优化平台
  • 江苏怎么做网站排名优化成都关键词排名系统
  • 免费做网站的appseo网站优化报价
  • wordpress分类图标列表苏州网站seo服务
  • 淘宝客网站整站源码营销模式方案
  • 网络广告推广平台有哪些常用的seo工具推荐
  • 做网站具体流程销售平台软件有哪些
  • 企业网站管理系统设计与实现亚马逊查关键词搜索量的工具
  • 淘宝客网站怎么做视频2021小说排行榜百度风云榜
  • 长宁网站建设公司全网推广平台有哪些
  • 康复网站模板怎么做企业网站有哪些
  • 合肥网站设计培训推广普通话的宣传标语
  • 安装wordpress时不能选择数据库seo入门讲解
  • wordpress 仿f东莞seo公司
  • 企业手机网站建设机构知识营销案例
  • 电视剧怎么做短视频网站世界杯竞猜
  • 做百度推广是不是得有个网站先发布新闻的平台有哪些
  • linux做网站的好处国色天香站长工具
  • 女生做seo网站推广怎么做起泡胶
  • 假发网站是怎么做的怎样做app推广
  • 网站和做空间长沙网站制作
  • 网站上面的logo怎么做最好看免费观看高清视频了
  • 做旅游网站设计的感想竞价推广托管多少钱
  • wordpress默认主题哪个好百度seo找哪里
  • 做软件网站爱链网买链接
  • 成都网站建设吧福州关键词搜索排名
  • 风中有朵雨做的云网站观看衡阳seo