一个.h文件 从网上下的代码
记录下
#pragma once
#include <mutex>
#include <queue>
#include <functional>
#include <future>
#include <thread>
#include <utility>
#include <vector>
// Thread safe implementation of a Queue using a std::queue
template <typename T>
class SafeQueue
{
private:
std::queue<T> m_queue; //利用模板函数构造队列
std::mutex m_mutex; // 访问互斥信号量
int max_size ;
public:
SafeQueue() { max_size = 10; };
SafeQueue(int size) { max_size = size; };
SafeQueue(SafeQueue &&other) {}
~SafeQueue() {}
bool empty() // 返回队列是否为空
{
std::unique_lock<std::mutex> lock(m_mutex); // 互斥信号变量加锁,防止m_queue被改变
return m_queue.empty();
}
int size()
{
std::unique_lock<std::mutex> lock(m_mutex); // 互斥信号变量加锁,防止m_queue被改变
return m_queue.size();
}
// 队列添加元素
bool push_data(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex);
if(m_queue.size() == max_size)
{
std::cout<<"Queue is full:"<<max_size<<std::endl;
return false;
}
m_queue.emplace(t);
return true;
}
// 队列取出元素
bool pop_data(T &t)
{
std::unique_lock<std::mutex> lock(m_mutex); // 队列加锁
if (m_queue.empty())
return false;
t = std::move(m_queue.front()); // 取出队首元素,返回队首元素值,并进行右值引用
m_queue.pop(); // 弹出入队的第一个元素
return true;
}
};
class BlackBox
{
private:
class Ari // 内置线程工作类
{
private:
int m_id; // 工作id
BlackBox &m_pool; // 所属线程池
public:
// 构造函数
Ari(BlackBox &_pool, const int id) :m_pool(_pool) ,m_id(id)
{
std::cout<<__func__<<" id:"<<m_id<<std::endl;
}
// 重载()操作
void operator()()
{
std::function<void()> func; // 定义基础函数类func
bool get_success; // 是否正在取出队列中元素
while (!m_pool.m_shutdown)
{
{
// 为线程环境加锁,互访问工作线程的休眠和唤醒
std::unique_lock<std::mutex> lock(m_pool.m_conditional_mutex);
// 如果任务队列为空,阻塞当前线程
if (m_pool.m_queue.empty())
{
m_pool.m_conditional_lock.wait(lock); // 等待条件变量通知,开启线程
}
// 取出任务队列中的元素
get_success = m_pool.m_queue.pop_data(func);
}
// 如果成功取出,执行工作函数
if (get_success)
{
func();
}
}
}
};
bool m_shutdown; // 线程池是否关闭
SafeQueue<std::function<void()>> m_queue; // 执行函数安全队列,即任务队列
std::vector<std::thread> m_threads; // 工作线程队列
std::mutex m_conditional_mutex; // 线程休眠锁互斥变量
std::condition_variable m_conditional_lock; // 线程环境锁,可以让线程处于休眠或者唤醒状态
public:
// 线程池构造函数
BlackBox(const int n_threads = 4)
: m_threads(std::vector<std::thread>(n_threads)), m_shutdown(false)
{
std::cout<<__func__<<std::endl;
}
~BlackBox()
{
std::cout<<__func__<<std::endl;
}
BlackBox(const BlackBox &) = delete;
BlackBox(BlackBox &&) = delete;
BlackBox &operator=(const BlackBox &) = delete;
BlackBox &operator=(BlackBox &&) = delete;
// Inits thread pool
void init()
{
for (int i = 0; i < m_threads.size(); ++i)
{
m_threads.at(i) = std::thread(Ari(*this, i)); // 分配工作线程
}
}
int get_tasks()
{
return m_queue.size();
}
// Waits until threads finish their current task and shutdowns the pool
void shutdown()
{
m_shutdown = true;
m_conditional_lock.notify_all(); // 通知,唤醒所有工作线程
for (int i = 0; i < m_threads.size(); ++i)
{
if (m_threads.at(i).joinable()) // 判断线程是否在等待
{
m_threads.at(i).join(); // 将线程加入到等待队列
}
}
}
// Submit a function to be executed asynchronously by the pool
template <typename F, typename... Args>
auto AddTask(F &&f, Args &&...args) -> std::future<decltype(f(args...))>
{
// Create a function with bounded parameter ready to execute
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...); // 连接函数和参数定义,特殊函数类型,避免左右值错误
// Encapsulate it into a shared pointer in order to be able to copy construct
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
// Warp packaged task into void function
std::function<void()> warpper_func = [task_ptr]()
{
(*task_ptr)();
};
// 队列通用安全封包函数,并压入安全队列
m_queue.push_data(warpper_func);
// 唤醒一个等待中的线程
m_conditional_lock.notify_one();
// 返回先前注册的任务指针
return task_ptr->get_future();
}
};
使用 定义
初始化
使用
for循环那里 是一个类成员函数 目前是用lambada包装了一下
如果直接写成下面注释掉的模式 会报错
如果直接用std::thread方式起的话 这样写是可以的
但是 放到线程池中这么写就编译报错 目前还不清楚 原因
关闭:
等待队列 上面线程池的已经有了 只不过不是等待队列 稍加改造 如下:
#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
template <class Typename >
class BlockQueue{
public:
BlockQueue()
{
m_size = 10;
std::cout<<__func__<<" max queue size:"<<m_size <<std::endl;
};
explicit BlockQueue(int size)
{
m_size = size;
std::cout<<__func__<<" max queue size:"<<m_size <<std::endl;
}
~BlockQueue()
{
std::cout<<__func__<<std::endl;
}
bool empty()
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.empty();
}
int size()
{
std::unique_lock<std::mutex> lock(m_mutex);
return m_queue.size();
}
bool push_data(Typename &data)
{
std::unique_lock<std::mutex> lock(m_mutex);
if(m_queue.size() <m_size)
{
m_queue.emplace(data);
m_cond_var.notify_one();
return true;
}
return false;
}
bool pop_data(Typename &data)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_cond_var.wait(lock,[this]{
return !this->m_queue.empty();
});
if(m_queue.empty())
{
return false;
}
else
{
data = std::move(m_queue.front());
m_queue.pop();
return true;
}
}
private:
uint32 m_size;
std::mutex m_mutex;
std::condition_variable m_cond_var;
std::queue<Typename> m_queue;
};
定义:
初始化:
使用