muduo_base库学习笔记7——无界队列、有界队列及线程池的实现

2023-10-29

BlockingQueueBoundedBlockingQueue实质就是一个生产者消费者的模型

一、 BlockingQueue

在这里插入图片描述
只用了一个条件变量notEmpty_,不需要notFull_,因为无界嘛不用考虑满的情况,条件变量需要跟一个互斥量一起使用mutex_,队列直接用STL中的deque_
在这里插入图片描述
put()生产;
在这里插入图片描述生产中用MutexLockGuard调用Mutex_进行保护,生产了就通知消费者线程
take()消费;
在这里插入图片描述队列空的时候就等待,直到不为空跳出循环,能跳出循环那就断言一定不为空了, front返回第一个元素,然后第一个元素弹出来,这是配套操作!front–>pop

size()队列大小
在这里插入图片描述
队列的大小也需要保护,因为可能有多个线程进行访问

二、BoundedBlockingQueue

两个条件变量,队列是直接用的boost::circular_buffer的环形缓冲区,一个保护互斥量
在这里插入图片描述

成员函数多了一个capacity表示队列的总容量,
多了empty函数和full函数判断队列是否满了或者空了
在这里插入图片描述
生产之前需要判断条件是否满了,如果满了就等待
在这里插入图片描述
其余都简单

三、线程池ThreadPool实现

线程池问题本质上也是生产者消费者问题,外部线程可以想线程池中的任务添加任务,相当于“生产者”;一旦任务队列中有任务,就唤醒线程队列中的线程来执行这些任务,这些任务就相当于“消费者”
在这里插入图片描述
类图:
在这里插入图片描述
互斥量、条件变量、线程池的名称、线程类,内部存放一个ptr_vector的指针、队列,用deque实现,数据类型是Task、running表示线程池是否处于运行状态
构造函数、析构函数、启动线程池(启动个数固定)、关闭线程池、运行任务(往线程池的任务队列添加任务)、线程池中的线程要执行的函数、获取任务(线程池中的线程函数要去获取任务然后执行任务)

具体实现:
.h文件
几个成员函数的声明:
很清楚的步骤:构造函数(传递一个名字)、析构函数、start()启动线程池,run添加任务或者运行任务、 runInThread()线程池中的线程要执行的函数, take()获取任务

进入.cc文件看看一些详细的实现

1,start()启动线程池,启动的线程是固定个数的
用到了bind函数!

void ThreadPool::start(int numThreads)//numThreads个
{
  assert(threads_.empty()); // 断言线程池是空的
  running_ = true; // 运行状态标记置为true
  threads_.reserve(numThreads); // 为线程池预留指定大小的空间
  // 创建线程
  for (int i = 0; i < numThreads; ++i)
  {
    char id[32];
    snprintf(id, sizeof id, "%d", i);
    threads_.push_back(new muduo::Thread(
          boost::bind(&ThreadPool::runInThread, this), name_+id));//绑定runInThread
    threads_[i].start();//启动线程,即启动bind的runInThread
  }
}

2,runInThread函数

void ThreadPool::runInThread()
{
  try
  {
    if (threadInitCallback_)
    {
      threadInitCallback_();
    }
    while (running_)//在start的时候就已经置为true了
    {//在这个循环中执行
      Task task(take());//take获取任务
      if (task)//取出了任务,只要这个任务不空
      {
        task();//我们就执行任务
      }
    }
  }
  catch (const Exception& ex)
  {
    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
    abort();
  }
  catch (const std::exception& ex)
  {
    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
    fprintf(stderr, "reason: %s\n", ex.what());
    abort();
  }
  catch (...)
  {
    fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str());
    throw; // rethrow
  }
}

3, take()获取任务

// 任务分配函数(获取任务)
// 线程池函数或者线程池里面的函数都可以到这里取出一个任务
// 然后在自己的线程中执行任务,返回一个任务指针  
ThreadPool::Task ThreadPool::take()  
{  
  MutexLockGuard lock(mutex_);  
  // always use a while-loop, due to spurious wakeup(虚假唤醒)
  while (queue_.empty() && running_)  // 任务队列为空且线程池处于运行状态,需要等待任务的到来
  {  
    cond_.wait();  
  }  
  Task task;  //任务来了,队列不空了就可以取任务
  if(!queue_.empty())  
  {  
    // 获取任务并弹出
    task = queue_.front();  
    queue_.pop_front();  
  }  
  return task;  //返回任务
} 

4,run() 执行任务

void ThreadPool::run(const Task& task)  
{  
  // 如果线程池没有线程,那么直接执行任务
  // 也就是说假设没有消费者,那么生产者直接消费产品,而不把任务加入任务队列
  if (threads_.empty())  
  {  
    task();  
  }  
  // 如果线程池有线程,则将任务添加到任务队列  
  else  
  {  
    MutexLockGuard lock(mutex_);   
    queue_.push_back(task);  
    cond_.notify();  
  }  
}  

5,stop() 关闭线程池

void ThreadPool::stop()
{
  {
  MutexLockGuard lock(mutex_);
  running_ = false; // 运行状态标识置为false
  cond_.notifyAll(); // 通知所有线程
  }
  // 等待所有线程关闭
  // boost::bind调用类成员函数时需要传入类成员函数指针、类对象指针...
  for_each(threads_.begin(),
           threads_.end(),
           boost::bind(&muduo::Thread::join, _1));
}

//测试代码:

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

muduo_base库学习笔记7——无界队列、有界队列及线程池的实现 的相关文章

  • Ubuntu (20.4,最新版)安装及简单入门操作

    1 打开VMare WorkStation 点击文件 gt 新建虚拟机 gt 找到宿主机内部Ubuntu镜像的位置 镜像下载位置 https msdn itellyou cn https next itellyou cn 新版地址 Ubun
  • Java代码审计

    一 java编译篇 java编译过程 Java源代码 编译 gt Java字节码 解释器 gt 机器码 Java源代码 编译器 gt jvm可执行的Java字节码 jvm解释器 gt 机器可执行的二进制机器码 gt 程序运行 采用字节码的好
  • (一)Redis: 基于 Key-Value 的存储系统

    1 Redis 介绍与安装 1 1 Redis 基本介绍 Redis 是一种基于 Key Value 的存储系统 可用作数据库 缓存和消息中间件等 仓库地址 https github com redis redis Redis is an
  • Linux火狐浏览器无法看视频,Ubuntu使用火狐浏览器无法播放视频如何解决

    Ubuntu使用火狐浏览器无法播放视频如何解决 发布时间 2020 11 07 17 16 00 来源 亿速云 阅读 156 作者 Leah 今天就跟大家聊聊有关Ubuntu使用火狐浏览器无法播放视频如何解决 可能很多人都不太了解 为了让大
  • 取消计算机硬盘自检,教你电脑开机自检如何关闭

    教你电脑开机自检如何关闭 电脑开机自检如何关闭 1 首先 打开 系统属性 在我的电脑上点右键 属性 或者在控制面板里打开 系统 快捷键win pause break 点 高级 选项卡 在 启动和故障恢复 区里打开 设置 去掉 系统启动 区里
  • 一款好用Ventoy启动盘制作方法

    Ventoy是一个制作可启动U盘的开源工具 有了Ventoy你就无需反复地格式化U盘 你只需要把 ISO WIM IMG VHD x EFI 等类型的文件直接拷贝到U盘里面就可以启动了 无需其他操作 你可以一次性拷贝很多个不同类型的镜像文件
  • .npy文件的读取

    npy文件是numpy专用的二进制文件 以读取x npy文件为例 1 在桌面新建一个文件夹命名为test 将x npy文件放入该文件夹内 2 运行代码 import numpy as np x np load C Users 用户名 Des
  • SLAM能用的传感器

    搞懂RTK定位 看这一篇就够了 知乎 zhihu com
  • Unity基础笔记(7)—— 资源管理

    Unity资源管理 一 资源导入和导出 资源导入 将打包好的unitypackage文件直接拖拽至窗口中 Unity 会自动解析包 再点击 import 即可导入资源 资源导出 右键点击要导出的资源文件夹 点击 export 导出资源 预制
  • 编译mono-debugger-2.4出错

    usr bin ld cannot find ltermcapcollect2 ld 返回 1make fileman 错误 1 echo PKG CONFIG PATH To set the PKG CONFIG PATH value u

随机推荐

  • 使用jprofiler分析dump文件一个实例

    1 jstat 命令先分析一下 一次fullgc之后 old 老年代使用比例 只降低2 应该有什么大的对象常驻内存 2 可以使用jmap 命令查看对象大小 这里后面使用jprofiler 就没用这个命令 jmap histo live 72
  • 如何使用Python读写JSON文件

    1 读取JSON文件 假设我们有一个名为 data json 的文件 其内容如下 name Alice age 30 city New York 我们可以使用Python中的json模块来读取该文件并将其存储为Python对象 以下是一个读
  • NGINX proxy服务器

    1 代理原理 正向代理 内网客户机通过代理访问互联网 通常要设置代理服务器地址和端口 反向代理 外网用户通过代理访问内网服务器 内网服务器无感知 正向代理与反向代理的区别是 正向代理即是客户端代理 代理客户端 服务端不知道实际发起请求的客户
  • 西工大图书馆分拣经历的数学建模角度思考

    今天下午没课于是乎去图书馆做志愿 志愿内容简单来讲就是分拣书籍 装箱子 运走的三部曲 工作需要我们的耐心和细致 同时也要求很好的体力 做的时候我还在思考这样的一个问题 就是这件事情从数学建模角度能不能分析分析 我们所需要做出的模型假设 仅供
  • 外贸业务员专用的18个英文学习网站!

    今天 我收集了一些非常实用的英语网站 包括信息 翻译和口语等方面练习 01英语学习网站 1 https www businessenglishsite com 这个网站是由在商业领域拥有丰富经验的专业人士创建的 他们每天都使用商业英语 因此
  • WebShell工具特征流量分析合集

    目录 中国蚁剑流量抓包分析 配置代理 数据包分析 特征 中国菜刀流量抓包分析 数据包分析 特征 冰蝎流量抓包分析 配置代理 自带PhpWebshell分析 base64编码 数据包分析 弱特征 强特征 哥斯拉流量抓包分析 配置代理 生成we
  • SpringBoot异常处理

    我们在实际开发中 会因为各种问题而导致无法正常访问网址 网站的对象是群众 如果出现各种的报错信息 对于用户的体验是非常的不好的 所以我们需要对项目的内部进行异常处理 保证用户的体验舒爽 目录 1 异常处理一 默认异常处理机制 1 导入前端模
  • OneNet平台对接记录

    手头有一台支持中移动的OneNet平台的接口的烟感设备 刚好可以用来了解一下移动搭建的这套开放平台 OneNet平台简介 OneNet平台是中国移动物联网公司推出的物联网解决方案平台 对于集成了移动的物联网模块 NB IOT模块的设备 目前
  • Linux内核编译+Busybox文件系统制作(基础)

    本人小白纯属爱好折腾了好久 希望分享对小白有所帮助 linux 5 15 1 5 14 14版本都可以 编译linux 4 9 229 出错提示 cc1 error fcf protection is not compatible with
  • 十大C++实战项目,你会几个?【高薪必备】

    市面上有很多C 的实战项目 从简单到进阶 学习每个项目都可以掌握相应的知识点 如果你还是C 新手的话 那么这个C 的项目列表你可以拿去练手实战开发 毕竟学编程动手实践是少不了的 如果你不知道C 可以用来做哪些项目 可以应用在哪些地方 那么
  • 解决临时表空间不足

    第一种方法 数据库服务器切换到 oracle的根目录执行 su oracle oracle edzxbsdb source bash profile oracle edzxbsdb sqlplus as sysdba 进入sql SQL g
  • bat脚本-卸载并重新安装apk,强制关闭app并重新启动app

    卸载并重新安装apk echo off echo echo Get devices adb devices gt devices txt echo echo restartApp for f skip 1 tokens 1 delims i
  • 头条号如何快速涨100W+粉丝?

    最近一些做头条的朋友和我反映 最近头条的流量很不错 给账号的扶持很大 劝诫我们要抓住这次机会 01 提高爆文产出率 粗看是句废话 但其中藏有奥妙 依靠爆款优质内容涨粉看似 低效 但始终是最根本的途径 由此吸引的粉丝 忠诚度极高 小易这头条号
  • Go【gin和gorm框架】实现紧急事件登记的接口

    简单来说 就是接受前端微信小程序发来的数据保存到数据库 这是我写的第二个接口 相比前一个要稍微简单一些 而且因为前端页面也是我写的 参数类型自然是无缝对接 前端页面大概长这个样子 先用apifox模拟发送请求测试 apifox可以直接复制J
  • python 字符串长度

    Python是一种高级编程语言 它具有简单易学 可读性强 功能强大等特点 因此在各个领域都有广泛的应用 在Python中 字符串是一种非常重要的数据类型 它可以用来存储文本信息 比如说一段话 一篇文章等等 字符串的长度是指其中字符的个数 可
  • mysql查询 多门课程的平均成绩_数据分析中级 MySQL 任务6 总结复习

    0 入门 0 1 MySQL安装 Navicat安装 0 2 MySQL设置 Nacicat设置 包括链接点 unicode 8 0 3 创建表格 student course score teacher 1 简单查询 1 1 查询姓 猴
  • 2023年7月婴幼儿辅食市场数据分析(京东商品数据)

    随着人们对婴幼儿饮食健康的关注不断增加 市场对高品质 安全 营养丰富的辅食需求也日益旺盛 婴幼儿辅食市场增长放缓 但整体仍保持上升态势 鲸参谋数据显示 今年7月份 京东平台婴幼儿辅食市场的销量为1000万 同比增长约8 本月的总销额为3 7
  • ORM如何处理many -to -many的关系

    表之间的关联可以形成一张非常复杂的graph 但是我们对其进行抽象就会发现两个有关系的表之间只有两种可能 one to many 或者many to many many to many 时会加入一个关联表 所以这里讲述的是如何处理关联表映射
  • (一)pytorch单任务图像分类

    深度学习主要由 数据读取 网络模型 损失函数 优化器这四个部分构成 最开始不应该纠结于这些细节 应该先让代码跑起来再去研究代码是怎么写的 下面的代码只是训练部分的代码 并加上验证模型准确率的功能 1 项目分布 创建一个文件夹my data1
  • muduo_base库学习笔记7——无界队列、有界队列及线程池的实现

    BlockingQueue和BoundedBlockingQueue实质就是一个生产者消费者的模型 一 BlockingQueue 只用了一个条件变量notEmpty 不需要notFull 因为无界嘛不用考虑满的情况 条件变量需要跟一个互斥