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

将wordpress网站变成app广告资源对接平台

将wordpress网站变成app,广告资源对接平台,电子商务难学吗,帮人做传销网站违法吗目录 线程安全的单例模式 什么是单例模式 单例模式的特点 饿汉实现方式和懒汉实现方式 饿汉⽅式实现单例模式 懒汉⽅式实现单例模式 懒汉⽅式实现单例模式(线程安全版本) 单例式线程池 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/13231.html

相关文章:

  • 2018年静安区品牌网站建设做seo必须有网站吗
  • 请人做游戏的网站培训学校管理制度大全
  • 呼家楼街道网站建设常见网络营销推广方法
  • 网站制作要多少钱如何制作一个网页
  • 有哪些做批发出口的网站百度竞价点击软件
  • 网站开发程序制作域名备案企业网络营销青岛
  • 怎样做网站运营亚马逊seo什么意思
  • 杭州今日重点新闻新网站排名优化怎么做
  • 邵阳市城乡建设厅网站如何做推广最有效果
  • 专门找事做的网站珠海百度搜索排名优化
  • 汽车之家如何做团购网站平台怎么推广
  • 网站建设分配人员方案查排名
  • 怎么做营销型网站电商网页
  • 随州网站建设价格创建网站需要什么条件
  • 网站建设设计费会计分录网站创建公司
  • 绝对大气漂亮的响应式网站后台模板百度seo免费推广教程
  • 内容导购网站模板seo站点
  • 千图网素材下载网站北京百度seo服务
  • 企业为什么要建设网站德州网站建设优化
  • 青海省交通建设厅网站北京网站优化方案
  • 投诉做单骗子网站百家号优化
  • 小说网站建设需要什么百度自媒体怎么注册
  • 网站结构化数据外贸网站seo优化
  • 网站备案率是什么镇江百度关键词优化
  • 烟台h5网站建设网页模版
  • 怎么做属于自己的免费网站怎么有自己的网站
  • 山东网站建设哪家专业电商网站seo怎么做
  • 大型网站技术方案网络营销策略案例
  • wordpress 免费ssl证书上海优化网站方法
  • 网站制作要多长时间北京seo代理计费