基于C++11及std::thread实现的线程池

线程池源码:

#pragma once
#include <functional>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <memory>
#include <cassert> /*
* Example:
*
* // 初始回调
* void InitCb() {
* static int i = 0;
* printf("InitCb: %d\n", i++);
* }
*
* // 任务函数
* void TaskCb() {
* static int i = 0;
* printf("TaskCb: %d\n", i++);
* }
*
* // 实例化大小为10的线程池
* std::unique_ptr<ThreadPool> upTp(new ThreadPool(10, std::bind(InitCb)));
* // 启动5个线程
* upTp->Start(5);
* do {
* // 投递任务进行处理
* upTp->InputTask(std::bind(TaskCb));
* } while(true);
*
*/
class ThreadPool
{
public:
ThreadPool(const ThreadPool& other) = delete;
ThreadPool& operator=(const ThreadPool& other) = delete;
using Task = std::function<void()>; ThreadPool(size_t max_queue_size, Task cb)
: cb_(std::move(cb)),
max_queue_size_(max_queue_size),
running_(false)
{
} ~ThreadPool()
{
if (running_)
{
Stop();
}
} void Start(unsigned num_threads)
{
assert(threads_.empty());
running_ = true;
threads_.reserve(num_threads);
for (auto i = 0; i < num_threads; ++i)
{
threads_.emplace_back(new std::thread(&ThreadPool::Process, this, i));
} if (num_threads == 0 && cb_)
{
cb_();
}
} void Stop()
{
{
std::lock_guard<std::mutex> lk(mtx_);
running_ = false;
not_empty_cond_.notify_all();
} for (auto& th : threads_)
{
th->join();
}
} void InputTask(Task task)
{
if (threads_.empty())
{
task();
}
else
{
std::unique_lock<std::mutex> lk(mtx_);
while (IsFull())
{
not_full_cond_.wait(lk);
}
assert(!IsFull()); queue_.push_back(std::move(task));
not_empty_cond_.notify_one();
}
} private:
void Process(unsigned nId)
{
printf("current thread id: %d\n", nId);
try
{
if (cb_)
{
cb_();
} while (running_)
{
Task task(Pop());
if (task)
{
task();
}
}
}
catch (...)
{
// TODO
throw;
}
} Task Pop()
{
std::unique_lock<std::mutex> lk(mtx_);
while (queue_.empty() && running_)
{
not_empty_cond_.wait(lk);
} Task task;
if (!queue_.empty())
{
task = queue_.front();
queue_.pop_front();
if (max_queue_size_ > 0)
{
not_full_cond_.notify_one();
}
}
return task;
} bool IsFull()
{
return max_queue_size_ > 0 && queue_.size() >= max_queue_size_;
} mutable std::mutex mtx_;
std::condition_variable not_empty_cond_;
std::condition_variable not_full_cond_;
Task cb_;
std::vector<std::unique_ptr<std::thread>> threads_;
std::deque<Task> queue_;
size_t max_queue_size_;
bool running_;
};

参考:陈硕——《Linux多线程服务器编程》

【C++11应用】基于C++11及std::thread实现的线程池的更多相关文章

  1. C++ 11 笔记 (五) : std::thread

    这真是一个巨大的话题.我猜记录完善绝B需要一本书的容量. 所以..我只是略有了解,等以后用的深入了再慢慢补充吧. C++写多线程真是一个痛苦的事情,当初用过C语言的CreateThread,见过boo ...

  2. C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)

    要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...

  3. Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)

    昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...

  4. C++11多线程std::thread的简单使用

    在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上.但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有 ...

  5. 基于C++11的100行实现简单线程池

    基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...

  6. C++11 并发指南------std::thread 详解

    参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Int ...

  7. 基于C++11的线程池,简洁且可以带任意多的参数

    咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...

  8. 基于C++11的线程池(threadpool),简洁且可以带任意多的参数

    咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...

  9. c++11中关于`std::thread`线程传参的思考

    关于std::thread线程传参的思考 最重要要记住的一点是:参数要拷贝到线程独立内存中,不管是普通类型.还是引用类型. 对于传递参数是引用类型,需要注意: 1.当指向动态变量的指针(char *) ...

随机推荐

  1. P1359 租用游艇 && P3905 道路重建 ------Floyd算法

    P1359 租用游艇   原题链接https://www.luogu.org/problemnew/show/P1359 P3905 道路重建   原题链接https://www.luogu.org/ ...

  2. oracle面试题2

    1.题目要求 为管理岗位业务培训信息,建立3个表:S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号.学员姓名.所属单位.学员年龄C (C#,CN ) C#,CN 分别代表课程编号. ...

  3. JAVA之G1与CMS垃圾回收

    G1 GC,全称Garbage-FirstGarbage Collector,通过-XX:+UseG1GC参数来启用,作为体验版随着JDK 6u14版本面世,在JDK 7u4版本发行时被正式推出,相信 ...

  4. 来谈谈MySQL的临时表,到底是个什么东西,以及怎么样产生的

    介绍临时表之前,我们首先来看这么一句语句: CREATE TABLE `words` ( `id` ) NOT NULL AUTO_INCREMENT, `word` ) DEFAULT NULL, ...

  5. 2.JSON.stringify()Object

    JSON.stringify() JSON 通常用于与服务端交换数据. 在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符 ...

  6. RecyclerView进阶:使用ItemTouchHelper实现拖拽和侧滑删除

    现在RecyclerView的应用越来越广泛了,不同的应用场景需要其作出不同的改变.有时候我们可能需要实现侧滑删除的功能,比如知乎首页的侧滑删除,又或者长按Item进行拖动与其他Item进行位置的交换 ...

  7. 视图解析器InternalResourceViewResolver

    ModelAndView对象中即可以封装真实视图路径名,也可以封装视图路径的逻辑名,springmvc.xml 代码如下: <!-- 视图解析器(框架) --> <bean clas ...

  8. CentOS 7 最小化安装后的注意事项

    http://blog.csdn.net/f_srion/article/details/54910943 在VM虚拟机中安装CentOS 7 时 有时候顾虑到电脑硬件性能,我们需要最小化安装,而最小 ...

  9. 九十五:CMS系统之cms后台模板渲染

    定义一个宏,用于渲染static文件的时候,只需要传文件名就可以,上下两个“-”是解决渲染的时候源代码换行的情况 {% macro static(filename) -%} {{ url_for('s ...

  10. vue-cli2.x版本安装vue-cli建项目

    全局安装vue-cli 命令行输入: vue-cli版本在3以下 npm install --global vue-cli 安装vue-cli后,可以查看一下是否安装成功vue --version, ...