layout: post
title: C++进阶(二)C++新特性:智能指针、右值引用、lambda、多线程操作、function和bind、可变模板参数
description: C++进阶(二)C++新特性:智能指针、右值引用、lambda、多线程操作、function和bind、可变模板参数
tag: C++
zero_threadpool.h
#pragma once
//zero_threadpool.h
#ifndef ZERO_THREADPOOL_H
#define ZERO_THREADPOOL_H
#include
#include
#include
#include
#include
#include
#ifdef WIN32
#include
#else
#include
#endif
using namespace std;
void getNow(struct timeval* tv);
int64_t getNowMs();
#define TNOW getNow()
#define TNOWMS getNowMs()
/**
* @file zero_thread_pool.h
* @brief 线程池类,采用c++11来实现了,
* 使用说明:
* ZERO_ThreadPool tpool;
* tpool.init(5); //初始化线程池线程数
* //启动线程方式
* tpool.start();
* //将任务丢到线程池中
* tpool.exec(testFunction, 10); //参数和start相同
* //等待线程池结束
* tpool.waitForAllDone(1000); //参数<0时, 表示无限等待(注意有人调用stop也会退出)
* //此时: 外部需要结束线程池是调用
* tpool.stop();
* 注意:
* ZERO_ThreadPool::exec执行任务返回的是个future, 因此可以通过future异步获取结果, 比如:
* int testInt(int i)
* {
* return i;
* }
* auto f = tpool.exec(testInt, 5);
* cout << f.get() << endl; //当testInt在线程池中执行后, f.get()会返回数值5
*
* class Test
* {
* public:
* int test(int i);
* };
* Test t;
* auto f = tpool.exec(std::bind(&Test::test, &t, std::placeholders::_1), 10);
* //返回的future对象, 可以检查是否执行
* cout << f.get() << endl;
*/
class ZERO_ThreadPool
{
protected:
struct TaskFunc
{
TaskFunc(uint64_t expireTime) : _expireTime(expireTime)
{ }
std::function<void()> _func;
int64_t _expireTime = 0; //超时的绝对时间
};
typedef shared_ptr<TaskFunc> TaskFuncPtr;
public:
/**
*构造函数
*/
ZERO_ThreadPool();
/**
*析构函数,停止所有线程
*/
virtual ~ZERO_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();
/*
用线程池启动任务(F是function, Args是参数)
返回任务的future对象,可以通过这个对象来获取返回值
*/
template <class F, class... Args>
auto exec(F&& f, Args&&...args) -> std::future<decltype(f(args...))>
{
return exec(0, f, args...);
}
/*
用线程池启动任务(F是function,Args是参数)
timeoutMs:超时时间,单位ms(为0时不做超时控制),若任务超时,任务将被抛弃
返回任务的future对象,可以通过这个对象来获取返回值
*/
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(); // 唤醒阻塞的线程,可以考虑只有任务队列为空的情况再去notify
return task->get_future();
}
/*
等待当前任务队列中,所有工作全部结束(队列无任务)
millsecond 等待的时间(ms),-1,:永远等待
*/
bool waitForAllDone(int millsecond = -1);
protected:
/*
获取任务
return TaskFuncPtr
*/
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
zero_threadpool.cpp
#include "zero_threadpool.h"
ZERO_ThreadPool::ZERO_ThreadPool() : _threadNum(1), _bTerminate(false) {}
ZERO_ThreadPool::~ZERO_ThreadPool() { stop(); }
bool ZERO_ThreadPool::init(size_t num)
{
std::unique_lock<std::mutex> lock(_mutex);
// 假如线程队列仍有线程在运行,直接返回false
if (!_threads.empty())
{
return false;
}
_threadNum = num;
return true;
}
void ZERO_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] = nullptr;
}
std::unique_lock<std::mutex> lock(_mutex);
_threads.clear();
}
bool ZERO_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(&ZERO_ThreadPool::run, this));
}
return true;
}
bool ZERO_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 ZERO_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 (const std::exception&)
{
}
--_atomic;
// 任务都执行完毕了
std::unique_lock<std::mutex> lock(_mutex);
if (_atomic == 0 && _tasks.empty())
{
_condition.notify_all(); // 这里只是为了通知waitForAllDone
}
}
}
}
bool ZERO_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);
#endif
}
void getNow(struct 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;
}
main.cpp
#include
#include <../../zero_threadpool.h>
using namespace std;
void func0()
{
cout << "func0()" << endl;
}
void func1(int a)
{
cout << "func1 int =" << a << endl;
}
//void func1(string a)
//{
// cout << "func1 string =" << a << endl;
//}
void func2(int a, string b)
{
cout << "func2() a=" << a << ", b=" << b << endl;
}
void test1() // 简单测试线程池
{
ZERO_ThreadPool threadpool; // 封装一个线程池
threadpool.init(1); // 设置线程的数量
threadpool.start(); // 启动线程池,创建线程, 线程没有start,创建完毕后被调度
// 假如要执行的任务
// threadpool.exec(1000,func0); // 1000是超时1000的意思,目前没有起作用
threadpool.exec(func1, 10);
// threadpool.exec((void(*)(int))func1, 10); // 插入任务
// threadpool.exec((void(*)(string))func1, "king");
threadpool.exec(func2, 20, "darren"); // 插入任务
threadpool.waitForAllDone(); // 等待都执行完退出 运行函数 插入1000个任务, 等1000个任务执行完毕才退出
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() // 测试任务函数返回值
{
ZERO_ThreadPool threadpool;
threadpool.init(1);
threadpool.start(); // 启动线程池
// 假如要执行的任务
std::future<decltype (func1_future(0))> result1 = threadpool.exec(func1_future, 10);
std::future<string> result2 = threadpool.exec(func2_future, 20, "darren");
// auto result2 = threadpool.exec(func2_future, 20, "darren");
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;
}
// int test(string str) {
// cout << _name << ", str = " << str << endl;
// }
void setName(string name) {
_name = name;
}
string _name;
};
void test3() // 测试类对象函数的绑定
{
ZERO_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() // 简单测试线程池
{
ZERO_ThreadPool threadpool; // 封装一个线程池
threadpool.init(1); // 设置线程的数量
threadpool.start(); // 启动线程池,创建线程, 线程没有start,创建完毕后被调度
// 假如要执行的任务
threadpool.exec((void(*)(int, int))func2_1, 10, 20); // 插入任务
threadpool.exec((int(*)(string, string))func2_1, "king", " and darren");
threadpool.waitForAllDone(); // 等待都执行完退出 运行函数 插入1000个任务, 等1000个任务执行完毕才退出
threadpool.stop(); // 这里才是真正执行退出
}
int main()
{
// test1(); // 简单测试线程池
// test2(); // 测试任务函数返回值
// test3(); // 测试类对象函数的绑定
test4();
cout << "main finish!" << endl;
return 0;
}