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

买程序的网站怎样进行seo优化

买程序的网站,怎样进行seo优化,嘉兴网站关键字优化,做网站到哪里接单📝前言: 这篇文章我们来讲讲Linux——基于单例模式的线程池设计 🎬个人简介:努力学习ing 📋个人专栏:Linux 🎀CSDN主页 愚润求学 🌄其他专栏:C学习笔记,C语言…

📝前言:

这篇文章我们来讲讲Linux——基于单例模式的线程池设计

🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏


这里写目录标题

  • 一,设计框架
    • 1. 总体框架
    • 2. 线程池模块
      • 2.1 什么是线程池
      • 2.2 设计思路
    • 3. 什么是单例模式
      • 3.1 饿汉模式
      • 3.2 懒汉模式(更推荐)
  • 二,实现代码
  • 三,测试结果
  • 四,线程安全和重入问题
  • 五、锁的其他问题
    • 1. 死锁问题
    • 2. 死锁四个必要条件
    • 3. 避免死锁
  • 六、STL和智能指针的线程安全

一,设计框架

1. 总体框架

我们需要的模块

  • 日志Mylog:用于DEBUG
  • 线程MyThread:用于生成多个线程
  • 线程池ThreadPool,利用前两个模块来实现一个线程池

2. 线程池模块

2.1 什么是线程池

线程池 是一种多线程处理模式,属于池化技术的一种。它通过提前创建并管理一定数量的线程,重复利用这些线程处理任务,避免了频繁创建和销毁线程的开销,从而提升系统性能和资源利用率

2.2 设计思路

  • 我们用一个queue来存储待处理的任务
  • 用一个vector来存储线程

3. 什么是单例模式

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

  • 通常把构造函数,拷贝,赋值…设置成私有,或者直接禁用(在外部无法创建实例)
  • 只保留一个static实例成员,这样类在被加载的时候,这个实例就存在了。(static成员不属于任何一个对象,而属于类,只有一份)
    • 注意static成员的初始化是在类外的(但是属于类的一部分,可以访问类的私有成员)
  • 然后提供一个public的接口来返回这个实例给外部使用

3.1 饿汉模式

  • 加载类的时候,直接创建整个static实例成员
  • 问题:如果静态实例的体积大,则加载时间长

3.2 懒汉模式(更推荐)

  • 延迟加载,我只定义静态成员实例的指针。
  • 当真正使用到这个成员时,再创建并赋值给指针(这样可以提高内存使用率)
    • 即:在GetInstance时发现指针为空再创建

可是还有几个设计上的问题:

  • 没有实例,我们怎么调GetInstance创造实例?
    • 所以GetInstance也是Static
  • 获取实例不是线程安全的,要加锁(不然可能创建多个实例)
    • 这个锁是什么锁?也需要是static的锁,因为没实例的时候拿不到类的锁。

二,实现代码

细节我就不讲了,感兴趣的可以看注释

#pragma once
#include "MyThread.hpp"
#include "Mylog.hpp"
#include <vector>
#include <queue>
#include "Task.hpp"
#include <mutex>
#include <condition_variable>// 先不考虑单例模式
using namespace std;
using namespace tr;template <typename T> // 任务类型
class ThreadPool
{
private:ThreadPool(int th_num = 3): _th_num(th_num),_isrunning(false),_wait_thread(0){}void HandlerTask() // 单个线程处理任务的方法{while (true){LOG(LogLevel::DEBUG) << GetThreadName() << " is running";_mutex.lock();while (_tasks_queue.empty() && _isrunning) // 条件变量一定要注意虚假唤醒{_wait_thread++;// LOG(LogLevel::DEBUG) << GetThreadName() << " is waiting";_cond.wait(_mutex);// LOG(LogLevel::DEBUG) << GetThreadName() << " is waked";_wait_thread--; // 如果等待被唤醒(唤醒是由别的地方唤醒的)}// 如果还有任务就先不退if (_tasks_queue.empty() && !_isrunning){_mutex.unlock(); // 尽早释放锁LOG(LogLevel::DEBUG) << GetThreadName() << " quit";break;}T t = _tasks_queue.front();_tasks_queue.pop();_mutex.unlock(); // 尽早释放锁LOG(LogLevel::DEBUG) << GetThreadName() << " 获得一个任务...";t(); // 处理任务}}void Start() // 启动线程池{if (!_isrunning){LOG(LogLevel::DEBUG) << "启动线程池...";_isrunning = true;// 必须要先开空间(因为扩容不是线程安全的)// 1. 创建 Mythread 对象// 2. 启动线程(线程开始执行HandlerTask)// 3. vector扩容(移动现有线程对象,原来的迭代器失效)// 如果 3. 的时候有线程在执行 HandlerTask,则原 this 指针会失效(导致段错误)// 以上为个人理解_threads.reserve(_th_num);// lock_guard<mutex> lock(_mutex); 不能这样做,又是为什么呢???for (int i = 0; i < _th_num; i++){// 用 HandlerTask(需要捕捉 this指针) 构造 Mythread 临时对象(隐式类型转换),_threads.emplace_back([this](){HandlerTask();});}}elseLOG(LogLevel::DEBUG) << "线程池已经启动, 请勿重复启动...";}// 禁用拷贝和赋值ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;ThreadPool(const ThreadPool<T> &) = delete;public:static ThreadPool<T> *GetInstance(){if (_instance == nullptr){_lock.lock();if (_instance == nullptr) // 双层 if 判断,只有一个线程能拿到锁进入这里,不会全部线程都通过这个判断{_instance = new ThreadPool<T>();_instance->Start(); // 启动线程池LOG(LogLevel::DEBUG) << " 创建线程池单例" ;return _instance;}}LOG(LogLevel::DEBUG) << " 获取线程池单例";return _instance;}void Stop() // 暂停(结束)线程池{lock_guard<mutex> lock(_mutex);if (!_isrunning)return;_isrunning = false;// 唤醒所有线程,让线程知道 _isrunning 已经为 false 了_cond.notify_all();LOG(LogLevel::INFO) << "线程池退出...";}void Wait() // 等待所有线程{for (auto &th : _threads){// LOG(LogLevel::INFO) << th.GetName() << " 退出...";th.Join();}}void Enqueue(const T &task) // 入队任务{lock_guard<mutex> lock(_mutex);if (_isrunning){_tasks_queue.push(task);// LOG(LogLevel::INFO) << "插入了一个任务";if (_wait_thread > 0)_cond.notify_one();}}~ThreadPool(){}private:bool _isrunning;queue<T> _tasks_queue;vector<Mythread> _threads;int _th_num; // 线程数量int _wait_thread;mutex _mutex; // 标准库的锁不用初始化condition_variable_any _cond;static ThreadPool<T> *_instance; // 静态成员实例static mutex _lock;
};template <typename T>                              // 模板类静态成员初始化必须带 template <typename T>, 因为模版要实例化
ThreadPool<T> *ThreadPool<T>::_instance = nullptr; // 还要声明模版的作用域
template <typename T>
mutex ThreadPool<T>::_lock;

主体代码为上面这部分的,如果想要获取其中其他模块的代码,可以访问我的GIthub

三,测试结果

在这里插入图片描述
在这里插入图片描述

四,线程安全和重入问题

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

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

重入分两种:

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

线程安全不一定是可重入的,而可重入函数则⼀定是线程安全的

五、锁的其他问题

1. 死锁问题

死锁是指在⼀组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站⽤不会释放的资源⽽处于的⼀种永久等待状态。

  • 比如:一个公共资源的访问需要两把锁,但是现在线程 A 和线程 B各自占一个,并且都不愿意放,还不断申请对方的,导致两者都申请不到造成死锁
    在这里插入图片描述
  • 还比如,单线程死锁(自己带着锁,还自己把自己挂起了)

在这里插入图片描述

2. 死锁四个必要条件

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

3. 避免死锁

那就是破坏死锁的四个必要条件,使之不满足…
有避免死锁的算法:银行家算法、死锁检测算法(这里不做介绍)

六、STL和智能指针的线程安全

  • STL 容器,不是线程安全的,比如扩容等操作,是可能被切换的
  • 智能指针本身是线程安全的,但是它们所指向的资源不是线程安全的

🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

http://www.hkea.cn/news/107730/

相关文章:

  • 成都圣都装饰装修公司北京搜索优化排名公司
  • 境外建设网站贴吧互联网域名注册查询
  • 广州建站工作室淘客推广怎么做
  • 中国最大的网站建设公司百度广告联盟点击一次多少钱
  • wordpress单页主题营销seo手机关键词网址
  • dedecms做电影网站韩国最新新闻
  • 哪个网站做废旧好如何在百度上发布自己的广告
  • 网站表单及商品列表详情模板如何搭建自己的网站
  • 网站域名登记证明百度高级搜索怎么用
  • 国外网站在国内做镜像站点网站搭建费用
  • 网站后台如何添加关键词软件开发公司
  • 手机做网站的网站windows优化大师卸载不了
  • 万网速成网站有哪些 功能自己的网站怎么推广
  • 邯郸哪有做网站的河南百度推广公司
  • 我是做环保类产品注册哪些浏览量大的网站推销自己的产品比较好呢西安网站seo优化公司
  • 网页传奇游戏排行昆明网络推广优化
  • 商城模板网站模板网站软文是什么
  • 校园网站推广方案怎么做网站排名推广工具
  • 深圳罗湖企业网站建设报价网络媒体发稿平台
  • 用别人公司域名做网站线下推广的渠道和方法
  • php mysql的网站开发外贸推广平台
  • 济南网站建设认可搜点网络能百度指数有三个功能模块
  • 网上商城网站建设意义在线代理浏览网页
  • 网站图片切换代码百度下载并安装最新版
  • 微信公众平台号申请注册入口杭州seo公司
  • 本周实时热点新闻事件seo文章代写一篇多少钱
  • 旺店通app手机企业版下载网站seo如何优化
  • 宝山区建设用地事务所网站网络公司有哪些
  • 用sql做简单的博客网站大连谷歌seo
  • 新手怎么学做网站就业培训机构有哪些