c++11
// #pragma once
#include <iostream>
#include <thread>
#include <memory>
#include <vector>
#include <queue>
#include <functional> // std:;function
#include <future> // std::packaged_task
#include <condition_variable>
#include <algorithm>
#include <mutex>
#include <atomic>
using namespace std;
class ThreadPool{
public:
using Ptr = std::shared_ptr<ThreadPool>;
public:
static Ptr GetInstance(const int& num_threads=8){
auto pThread = std::shared_ptr<ThreadPool>(new ThreadPool(num_threads));
return pThread;
}
~ThreadPool(){
if(_is_running){
wait();
stop();
}
}
void wait(){
std::unique_lock<mutex> lock(_task_mtx);
while(_running_task_num > 0 || _task_pool.size()>0){
_finished_cv.wait(lock);
}
}
void stop(){
_is_running = false;
_running_cv.notify_all();
for(auto& t:_thread_pool){
if(t.joinable()) t.join();
}
// _finished_cv.notify_all(); // ?不需要
}
template<typename FuncT, typename... ParamT>
auto submit(FuncT&& f, ParamT&&... params)->std::future<typename std::result_of<FuncT(ParamT...)>::type>
{
using returnType = typename std::result_of<FuncT(ParamT...)>::type;
auto task = std::make_shared<std::packaged_task<returnType()>>(
std::bind(std::forward<FuncT>(f), std::forward<ParamT>(params)...)
);
{
std::unique_lock<mutex> lock(_task_mtx);
_task_pool.emplace([task](){(*task)();});
}
_running_cv.notify_one();
return task->get_future();
}
private:
ThreadPool(const int& num_threads)
:_thread_num(min(num_threads, (int)std::thread::hardware_concurrency())), _is_running(true), _running_task_num(0)
{
for(int i=0;i<_thread_num;i++){
_thread_pool.emplace_back(
[this](){
std::function<void()> task;
while(true){
{
std::unique_lock<mutex> lock(_task_mtx);
while(_is_running && _task_pool.empty()) _running_cv.wait(lock);
if((!_is_running) && _task_pool.empty()) break;
task = std::move(_task_pool.front());
_task_pool.pop();
_running_task_num++;
}
task();
_running_task_num--;
_finished_cv.notify_all(); // 唤醒一个?
}
}
);
}
}
int _thread_num;
vector<std::thread> _thread_pool;
queue<std::function<void()>> _task_pool;
atomic<int> _running_task_num;
atomic<bool> _is_running;
std::condition_variable _running_cv;
std::condition_variable _finished_cv;
std::mutex _task_mtx;
};
// g++ -std=c++11 ThreadPool_c11.cpp -o ThreadPool_c11
int main(){
std::cout <<"std::thread::hardware_concurrency():"<<std::thread::hardware_concurrency() << std::endl;
int size = 5;
vector<int> nums(size);
for(int i=0; i<size; i++){
nums[i] = i;
}
auto func = [](int& i){
int tmp = i;
i = i*i;
std::cout<<"thread id:"<<std::this_thread::get_id() << " " << tmp << "^2: "<< i <<std::endl;
};
auto p = ThreadPool::GetInstance(10);
for(auto& n:nums){
p->submit(func, ref(n));
}
p->wait();
// std::this_thread::sleep_for(std::chrono::seconds(1));
for(auto& n:nums){
cout <<"n:" << n<<" ";
}
cout <<endl;
}
c++14
// threadpool.cpp
#include <iostream>
#include <thread>
#include <queue>
#include <atomic>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <future>
#include <memory>
#include <functional>
using namespace std;
class ThreadPool{
private:
int __thread_num;
atomic<bool> __is_run;
atomic<int> __run_num;
vector<std::thread> __thread_pool;
queue<std::function<void()>> __task_pool;
condition_variable __cv_run;
condition_variable __cv_finish;
mutex __task_mtx;
public:
ThreadPool(const int& threadnum);
~ThreadPool();
void wait();
void stop();
template<typename funT, typename... ParamT>
auto submit(funT&& f, ParamT&&... param);
};
ThreadPool::ThreadPool(const int& threadnum):__thread_num(threadnum), __is_run(true), __run_num(0)
{
for(int i=0; i< __thread_num; i++){
__thread_pool.emplace_back(
[this](){
std::function<void()> task;
while(true){
{
unique_lock<mutex> lock(__task_mtx);
__cv_run.wait(lock, [this](){return !(__is_run && __task_pool.empty());});
if(!__is_run && __task_pool.empty()) break;
task = std::move(__task_pool.front());
__task_pool.pop();
++__run_num;
}
task();
--__run_num;
__cv_finish.notify_one();
}
}
);
}
}
ThreadPool::~ThreadPool(){
if(__is_run){
wait();
stop();
}
}
void ThreadPool::wait(){
unique_lock<mutex> lock(__task_mtx);
__cv_finish.wait(lock, [this](){ return !(__run_num>0 || !__task_pool.empty());});
}
void ThreadPool::stop(){
__is_run = false;
__cv_run.notify_all();
for(auto& th : __thread_pool){
if(th.joinable()) th.join();
}
}
template<typename funT, typename... ParamT>
auto ThreadPool::submit(funT&& f, ParamT&&... param){
auto task = std::make_shared<std::packaged_task<decltype(f(param...))()>>(
std::bind(std::forward<funT>(f), std::forward<ParamT>(param)...)
);
{
unique_lock<mutex> lock(__task_mtx);
__task_pool.emplace([task](){
(*task)();
});
}
__cv_run.notify_one();
return task->get_future();
}
void sqr(int& value){
value *= value;
cout<<"thread id:"<<std::this_thread::get_id() << " value:"<<value <<endl;
}
// g++ -std=c++14 threadpool.cpp -o threadpool
int main(){
vector<int> nums;
for(int i=0; i<10;i++) nums.push_back(i);
auto p = new ThreadPool(10);
for(auto& num:nums){
p->submit(sqr, ref(num));
}
p->wait();
for(auto& num:nums){
cout <<"num:"<< num<<" ";
}
cout<<endl;
delete p;
}