看开源库的线程池
主要看线程池的三部分: init 回调函数 入队函数 (外加一个销毁函数)
而c++线程池,因为类封装在一起,可以先看 成员数据
先上完整代码,这是我稍稍魔改过的
// ThreadPool.h
#ifndef ThreadPool_H
#define ThreadPool_H
#include <cassert> //for assert
#include <future>
#include <functional>
#include <iostream>
#include <queue>
#include <mutex>
#include <memory>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
using namespace std;
void getNow(timeval *tv);
int64_t getNowMs();
#define TNOW getNow()
#define TNOWMS getNowMs()
class ThreadPool
{
public:
void exec_py(const std::function<void()> &f)
{
exec(f);
return;
}
ThreadPool(int size);
ThreadPool(){};
virtual ~ThreadPool();
bool init(size_t num);
size_t getThreadNum()
{
std::unique_lock<std::mutex> lock(_mutex);
return _threads.size();
}
size_t getJobNum()
{
std::unique_lock<std::mutex> lock(_mutex);
return _tasks.size();
}
void stop();
bool start(size_t num = 1);
template <class F, class... Args>
auto exec(F &&f, Args &&...args) -> std::future<decltype(f(args...))>
{
return exec(0, f, args...);
}
template <class F, class... Args>
auto exec(int64_t timeoutMs, F &&f, Args &&...args) -> std::future<decltype(f(args...))>
{
int64_t expireTime = (timeoutMs == 0 ? 0 : TNOWMS + timeoutMs);
using RetType = decltype(f(args...));
auto task = std::make_shared<std::packaged_task<RetType()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
TaskFuncPtr fPtr = std::make_shared<TaskFunc>(expireTime);
fPtr->_func = [task]() {
(*task)();
};
std::unique_lock<std::mutex> lock(_mutex);
_tasks.push(fPtr);
_condition.notify_one();
return task->get_future();
}
bool waitForAllDone(int millsecond = -1);
protected:
struct TaskFunc
{
TaskFunc(uint64_t expireTime) : _expireTime(expireTime)
{
}
std::function<void()> _func;
int64_t _expireTime = 0;
};
typedef shared_ptr<TaskFunc> TaskFuncPtr;
protected:
bool get(TaskFuncPtr &task);
bool isTerminate() { return _bTerminate; }
void run();
protected:
queue<TaskFuncPtr> _tasks;
std::vector<std::thread *> _threads;
std::mutex _mutex;
std::condition_variable _condition;
size_t _threadNum;
bool _bTerminate;
std::atomic<int> _atomic{0};
};
#endif // ThreadPool_H
#include "threadpool.h"
ThreadPool::ThreadPool(int size)
: _threadNum(1), _bTerminate(false)
{
start(size_t(size));
}
ThreadPool::~ThreadPool()
{
stop();
}
bool ThreadPool::init(size_t num)
{
std::unique_lock<std::mutex> lock(_mutex);
if (!_threads.empty())
{
return false;
}
if (num < 1)
{
_threadNum = 1;
}
else
_threadNum = num;
return true;
}
void ThreadPool::stop()
{
{
std::unique_lock<std::mutex> lock(_mutex);
_bTerminate = true;
_condition.notify_all();
}
for (size_t i = 0; i < _threads.size(); i++)
{
if (_threads[i]->joinable())
{
_threads[i]->join();
}
delete _threads[i];
_threads[i] = NULL;
}
std::unique_lock<std::mutex> lock(_mutex);
_threads.clear();
}
bool ThreadPool::start(size_t num)
{
init(num);
std::unique_lock<std::mutex> lock(_mutex);
if (!_threads.empty())
{
return false;
}
for (size_t i = 0; i < _threadNum; i++)
{
_threads.push_back(new thread(&ThreadPool::run, this));
}
return true;
}
bool ThreadPool::get(TaskFuncPtr &task)
{
std::unique_lock<std::mutex> lock(_mutex);
if (_tasks.empty())
{
_condition.wait(lock, [this]
{ return _bTerminate || !_tasks.empty(); });
}
if (_bTerminate)
return false;
if (!_tasks.empty())
{
task = std::move(_tasks.front()); // 使用了移动语义
_tasks.pop();
return true;
}
return false;
}
void ThreadPool::run()
{
while (!isTerminate())
{
TaskFuncPtr task;
bool ok = get(task);
if (ok)
{
++_atomic;
try
{
if (task->_expireTime != 0 && task->_expireTime < TNOWMS)
{
//超时任务,是否需要处理?
}
else
{
task->_func();
}
}
catch (...)
{
}
--_atomic;
std::unique_lock<std::mutex> lock(_mutex);
if (_atomic == 0 && _tasks.empty())
{
_condition.notify_all();
}
}
}
}
bool ThreadPool::waitForAllDone(int millsecond)
{
std::unique_lock<std::mutex> lock(_mutex);
if (_tasks.empty())
return true;
if (millsecond < 0)
{
_condition.wait(lock, [this]
{ return _tasks.empty(); });
return true;
}
else
{
return _condition.wait_for(lock, std::chrono::milliseconds(millsecond), [this]
{ return _tasks.empty(); });
}
}
int gettimeofday(struct timeval &tv)
{
#if WIN32
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1;
clock = mktime(&tm);
tv.tv_sec = clock;
tv.tv_usec = wtm.wMilliseconds * 1000;
return 0;
#else
return ::gettimeofday(&tv, 0);
#endif
}
void getNow(timeval *tv)
{
#if TARGET_PLATFORM_IOS || TARGET_PLATFORM_LINUX
int idx = _buf_idx;
*tv = _t[idx];
if (fabs(_cpu_cycle - 0) < 0.0001 && _use_tsc)
{
addTimeOffset(*tv, idx);
}
else
{
TC_Common::gettimeofday(*tv);
}
#else
gettimeofday(*tv);
#endif
}
int64_t getNowMs()
{
struct timeval tv;
getNow(&tv);
return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
}
queue<TaskFuncPtr> _tasks; //任务队列
std::vector<std::thread *> _threads;//线程队列
std::mutex _mutex;//互斥锁,用来配合条件变量
std::condition_variable _condition;//条件变量,用来唤醒线程
size_t _threadNum;//线程池中线程的数量
bool _bTerminate; //结束标识符,当想把线程池结束的时候讲这个变量设置为true
//注:对死循环的任务无效,不过死循环的任务就不要用线程池管理了
std::atomic<int> _atomic{0}; //原子锁,用来防止虚假唤醒
线程池主要就三个部分,接下来依次介绍
TODO