#ifndef THREADPOOL_H
#define THREADPOOL_H
#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 {
protected:
struct TaskFunc {
TaskFunc(uint64_t expireTime): _expireTime(expireTime){}
std::function<void()> _func;
int64_t _expireTime = 0;
};
typedef shared_ptr<TaskFunc> TaskFuncPtr;
public:
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();
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:
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
#include "threadpool.h"
ThreadPool::ThreadPool()
: _threadNum(1), _bTerminate(false)
{}
ThreadPool::~ThreadPool() {
stop();
}
bool ThreadPool::init(size_t num) {
std::unique_lock<std::mutex> lock(_mutex);
if (!_threads.empty()) {
return false;
}
_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() {
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;
}
#include <iostream>
#include "threadpool.h"
using namespace std;
void func0() {
cout << "func0()" << endl;
}
void func1(int a) {
cout << "func1 int =" << a << endl;
}
void func2(int a, string b) {
cout << "func2() a=" << a << ", b=" << b<< endl;
}
void test1() {
ThreadPool threadpool;
threadpool.init(1);
threadpool.start();
threadpool.exec(1000,func0);
threadpool.exec(func1, 10);
threadpool.exec(func2, 20, "hello");
threadpool.waitForAllDone();
threadpool.stop();
}
int func1_future(int a) {
cout << "func1() a=" << a << endl;
return a;
}
string func2_future(int a, string b) {
cout << "func1() a=" << a << ", b=" << b<< endl;
return b;
}
void test2() {
ThreadPool threadpool;
threadpool.init(1);
threadpool.start();
std::future<decltype (func1_future(0))> result1 = threadpool.exec(func1_future, 10);
auto result2 = threadpool.exec(func2_future, 20, "hello");
std::cout << "result1: " << result1.get() << std::endl;
std::cout << "result2: " << result2.get() << std::endl;
threadpool.waitForAllDone();
threadpool.stop();
}
class Test {
public:
int test(int i){
cout << _name << ", i = " << i << endl;
return i;
}
void setName(string name){
_name = name;
}
string _name;
};
void test3() {
ThreadPool threadpool;
threadpool.init(1);
threadpool.start();
Test t1;
Test t2;
t1.setName("Test1");
t2.setName("Test2");
auto f1 = threadpool.exec(std::bind(&Test::test, &t1, std::placeholders::_1), 10);
auto f2 = threadpool.exec(std::bind(&Test::test, &t2, std::placeholders::_1), 20);
threadpool.waitForAllDone();
cout << "t1 " << f1.get() << endl;
cout << "t2 " << f2.get() << endl;
}
void func2_1(int a, int b) {
cout << "func2_1 a + b = " << a+b << endl;
}
int func2_1(string a, string b) {
cout << "func2_1 a + b = " << a << b<< endl;
return 0;
}
void test4() {
ThreadPool threadpool;
threadpool.init(1);
threadpool.start();
threadpool.exec((void(*)(int, int))func2_1, 10, 20);
threadpool.exec((int(*)(string, string))func2_1, "Tom", " and Jerry");
threadpool.waitForAllDone();
threadpool.stop();
}
int main() {
test4();
cout << "main finish!" << endl;
return 0;
}