正常线程执行完任务后即会销毁,而反复创建和销毁线程的代价较高,Fixed 线程池中的线程一直存在,会不断查看任务队列是否有新任务完成,当提交任务给线程池时,若当时线程池已满会返回错误;

1. ThreadPool

线程池可以通过start 开启并传入最大线程数控制线程池规模:

// ThreadPool pool;
// pool.start(4);
void ThreadPool::start(int initThreadSize) {initThreadSize_ = initThreadSize;for (int i = 0; i < initThreadSize_; i++) {auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this));threads_.emplace_back(std::move(ptr));}for (int i = 0; i < initThreadSize_; i++) {threads_[i]->start();}

线程池拥有vector 管理含Thread 资源的智能指针,Thread 类由C++11 thread 实现线程功能,thread 执行函数由ThreadPool::threadFunc 决定,因为本质上所有线程做的都是同一件事:向线程池中索要执行任务;

void ThreadPool::threadFunc() {while(true) {std::shared_ptr<Task> curTask;{std::unique_lock<std::mutex> lock(taskQueMtx_);notEmpty_.wait(lock, [&]() -> bool { return taskQue_.size() > 0; });curTask = taskQue_.front();taskQue_.pop();taskSize_--;if (taskQue_.size() > 0) {notEmpty_.notify_all();}notFull_.notify_all();}if (curTask != nullptr) {curTask->exec();}}

ThreadPool 使用生产者消费者模型,当任务队列有任务时,notEmpty 信号量苏醒,取任务执行并通知,因为执行任务导致队列缩短,因此notFull 通知,可以来提交任务了;(注意增加的Block,不然taskQueMtx_ 会导致其他线程一直等待从而只有一个线程在实际运行;

Result ThreadPool::submitTask(std::shared_ptr<Task> ptr) {std::unique_lock<std::mutex> lock(taskQueMtx_);if (!notFull_.wait_for(lock, std::chrono::seconds(1), [&]()->bool{return taskQue_.size() < taskQueMaxThreshHold_;})) {std::cerr<<"task queue is full, submitTask failed.\n";return Result(ptr, false);}taskQue_.emplace(ptr);taskSize_++;notEmpty_.notify_all();return Result(ptr);
}

提交任务会等待队列空出位置,不然报错,若有空余,添入队列并通知notEmpty 信号量;

2. Thread

Thread 很简单,注意开启detach;

Thread::Thread(ThreadFunc threadFunc) {func_ = threadFunc;
}Thread::~Thread() {}void Thread::start() {std::thread t(func_);t.detach();
}

3. Task

Task 为所有任务的父类,当有定义任务时,继承Task 并重写run() 即可:

class Task {public:void exec();void setResult(Result*);virtual Any run() = 0;
private:Result* result_;
};void Task::exec() {if (result_ != nullptr) {auto x = run();result_->setVal(std::move(x));}
}void Task::setResult(Result* r) {result_ = r;
}

考虑到线程执行完会有返回值,但是不同任务返回值可能不一样,引入Any 上帝类和 Result 结果类;

3. Any And Result

any C++17 中已经由标准实现,这儿手撸一个无值语义的Any,大致思路和下面标准类似:

any a = 1;
cout<<any_cast<int>(a)<<endl;
a = 2.2;
cout<<any_cast<double>(a)<<endl;
// >> 1
// >> 2.2
class Any {public:Any() = default;~Any() = default;Any(const Any &) = delete;Any &operator=(const Any &) = delete;Any(Any &&) = default;Any &operator=(Any &&) = default;template<typename T>Any(T data) : base_(std::make_unique<Derived < T>>(data)) {std::cout<<"T is constructing "<<data<<std::endl;}template<typename T>T cast() {auto pd = dynamic_cast<Derived <T> *>(base_.get());if (pd == nullptr) {throw "type is unmatched";}return pd->get();}private:class Base {public:virtual ~Base() = default;};template<typename T>class Derived : public Base {public:Derived(T data) : data_(data) {}~Derived() = default;T get() {return data_;}private:T data_;};private:std::unique_ptr<Base> base_;
};

Result 存放了Any 作为接受线程返回值,但是Result 获取有一个前提条件,任务线程必须先执行完再获取值,所以Result 生命周期必须比Task 长,而且Task 和 Result 有相互关系,Task 执行完向Result 存值,Result 持有shared_ptr 并在构造时向Task 传递;

实现的思路很简单,通过信号量同步:

Result::Result(std::shared_ptr<Task> sp, bool isValid): sp_(sp), isValid_(isValid){sp_->setResult(this);
}Any Result::get() {if (!isValid_) {return "";}sem_.wait();return std::move(any_);
}void Result::setVal(Any&& any) {any_ = std::move(any);sem_.post();
}

4. How to Use

class MyTask : public Task {public:MyTask(int begin, int end) : begin_(begin), end_(end) {}Any run() override {std::cout << "tid: " << std::this_thread::get_id() << " begin!\n";int sum = 0;for (int i = begin_; i <= end_; i++) {sum += i;}std::cout << "tid: " << std::this_thread::get_id() << " end!\n";return sum;}private:int begin_;int end_;
};int main() {ThreadPool pool;pool.start(4);Result res1 = pool.submitTask(std::make_shared<MyTask>(1, 1000));Result res2 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));Result res3 = pool.submitTask(std::make_shared<MyTask>(2001, 3000));int res = res1.get().cast<int>() + res2.get().cast<int>() + res3.get().cast<int>();for (int i = 1; i <= 3000; i++) {res -= i;}assert(res == 0);exit(0);
}

assert 正常通过!

(一)Fixed ThreadPool相关推荐

  1. ELK安装文档及相关优化

    前言:随着硬件成本的不断低廉,我们可以存储更多数据内容,也会对各数据加以利用,其中一项很重要的数据内容便是日志文件,无论是访问日志还是系统日志或是应用日志,都显得十分重要,而怎么加以利用一直是一个难题 ...

  2. elk 的报错和优化

    参数调整 elasticsearch.yml配置文件里面,调整http.max_content_length: 500mb 这个默认就100m 建议调大 之前有过报错 #如果队列满了logstash就 ...

  3. html5调用系统声音1s响一次_记录一次系统性能调优过程

    在线上环境,由于业务场景需要,要求程序能够在普通的4G机器中依然正常运行. 而原来的环境配置为8核16G,微服务部署,一共有6个功能模块. 而现在要求在一台4核4G的设备上正常运行. 问题清单 模块合 ...

  4. Elasticsearch线程池介绍

    每个Elasticsearch节点内部都维护着多个线程池,如index.search.get.bulk等,用户可以修改线程池的类型和大小,线程池默认大小跟CPU逻辑一致,本文基于最新的Elastics ...

  5. 【Elasticsearch】Elasticsearch CPU高排查思路

    1.概述 2.原因 可能导致ES CPU高的原因: 复杂的query查询 举例:我这边出现过200个组合wildcard query导致集群down掉的情况: 有大量的reindex操作 ES版本较低 ...

  6. elasticsearch 生产级别深度优化

    这是一篇转自别人的文章,真的讲的很详细.已经读了很多遍,分享给大家. 贴上原文地址(原文将了很多内容,这是优化方面摘取出来的):https://www.cnblogs.com/kevingrace/p ...

  7. elasticsearch 性能优化

    所有的修改都可以在elasticsearch.yml里面修改,也可以通过api来修改.推荐用api比较灵活 1.不同分片之间的数据同步是一个很大的花费,默认是1s同步,如果我们不要求实时性,我们可以执 ...

  8. Elasticsearch常用配置及性能参数

    Elasticsearch常用配置及性能参数 cluster.name: estest   集群名称 node.name: "testanya"  节点名称 node.master ...

  9. 触类旁通Elasticsearch:管理

    目录 一.模板 二.动态映射 三.分配感知 四.监控 1. 检查集群健康状况 2. 慢日志.热线程和线程池 3. 内存 4. 操作系统缓存 5. 存储限流 五.备份与恢复 1. 快照API 2. 将数 ...

最新文章

  1. PNAS-2018-玉米根际的大规模田间重复研究确定可遗传的微生物
  2. mysql默认几个库_MySQL 安装初始化mysql后,默认几个库介绍
  3. 深度学习(计算机视觉)面试中问题(一)
  4. java oci_java oracle oci方式连接
  5. 测试小白入门必知必会的8个测试工具
  6. JavaScriptSerializer类 对象序列化为JSON,JSON反序列化为对象
  7. 【报告分享】2020年中国人工智能商业落地研究报告.pdf(附下载链接)
  8. 巧用eXeScope修改win2000外观
  9. js实现键盘按键映射
  10. 面试官:如何实现单行/多行文本溢出的省略样式?
  11. 基于 AWS 的一站式分布式数据库测试体系,简单易上手|TiDB Hackathon 2020 优秀项目分享
  12. iPhone5s 换电池、修右上角翘起的悲催过程
  13. 项目1在线交流平台-7.构建安全高效的企业服务-5.redis高级数据结构应用-统计网站数据-独立访客和日活跃用户
  14. 【数据分析 R语言实战】学习笔记 第六章 参数估计与R实现(上)
  15. 《男人装》2006.05
  16. 8086汇编学习之[BX],CX寄存器与loop指令,ES寄存器等
  17. es6 取数组的第一个和最后一个_es6常用数组操作及技巧汇总
  18. 农学211高校食堂饭菜价格贵得离谱惹争议!学生:吃不起饭了!
  19. 衢州职业技术学院分数线平均计算机,衢州职业技术学院录取分数线2021是多少分(附历年录取分数线)...
  20. 《生命科学50讲》课程笔记10-自由意志

热门文章

  1. bigemap最近更新功能列表
  2. 关于DBA的一些学习(一)
  3. 3D美术人员Technical Artist(TA技术美术)的学习之旅(2)
  4. Mybatis中用到的设计模式
  5. Tarjan算法超详细讲解(割点割边强连通)
  6. adb 操作 快速点击屏幕
  7. 从感知机到Transformer,一文概述深度学习简史
  8. 关于Gson对日期的格式化
  9. Linux查看目录大小文件大小内存大小硬盘大小
  10. 不用U盘,电脑之间快速传输大文件,共享功能