【C++】C++11 多线程,类的多线程任务,线程池,任务队列的用法
文章目录
一、c++11多线程使用
示例:std::thread 多线程最简单用法
代码如下(示例):
std::thread t([](){
int a = 0;
a++
);
t.detach();
二、类任务与多线程
1.重载类的操作符()()
代码如下(示例):
class threadworker
{
public:
void operator()()
{
//do something
}
void operator()(int a)
{
//do something
}
}
2.使用
代码如下(示例):
threadworker th;
int n=0;
std::thread t(th);
std::thread t1(th,n)
3.类中循环线程
class threadLoopworker
{
public:
void operator()()
{
while (bLoop)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void Start()
{
std::thread loopThread(*this);
loopThread.detach();
}
void Eixt()
{
bLoop = false;
}
private:
bool bLoop = false;
};
二、类任务多线程.安全任务队列 Queue 与线程池的使用
1.安全队列实现
安全队列(示例):
#pragma once
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
using namespace std;
template <typename T>
class ThreadSafeQueue
{
private:
// 互斥必须使用mutable修饰 ,准许其发生变化, 否则没办法在const标记的对象中上锁和解锁
mutable std::mutex mut; std::queue<T> data_queue;
std::condition_variable data_cond;
public:
ThreadSafeQueue()
{
}
ThreadSafeQueue(ThreadSafeQueue const& other)
{
std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue;
}
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this] { return !this->data_queue.empty(); });
value = data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
unique_lock<mutex> lk(mut);
data_cond.wait(lk, [this] { return !this->data_queue.empty(); });
std::shared_ptr<T> res(make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<mutex> lk(mut);
if (data_queue.empty())
return false;
value = data_queue.front();
data_queue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool empty() const
{
// 如果不用 mutable 修饰 mutex 那就无法改变锁的状态
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
bool size()
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.size();
}
};
template<typename T>
class safequeue
{
private:
mutable std::queue<T>m_queue;
std::mutex m_mutex;
public:
safequeue()
{
}
safequeue(safequeue& other)
{
std::unique_lock<std::mutex>lock(other.m_mutex);
m_queue = other.m_queue;
}
~safequeue()
{
}
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();
}
void enqueue(T& t)
{
std::unique_lock<std::mutex>lock(m_mutex);
m_queue.emplace(&t);
}
bool dequeue(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;
}
};
2.线程池的实现
线程池代码(示例):
#include<mutex>
#include<vector>
#include"SafeQueue.h"
#include<functional>
#include<mutex>
#include<thread>
#include<condition_variable>
#include<future>
class Queuethreadpool
{
private:
class threadworker
{
private:
int m_id;
Queuethreadpool* m_pool;
public:
threadworker(const int id, Queuethreadpool* pool) :m_id(id), m_pool(pool) {}
void operator()()
{
std::function<void()> func;
while (!m_pool->m_shutdown)
{
if (m_pool->m_queueHighThread.empty()&& m_pool->m_queueThread.empty())
{
std::unique_lock<std::mutex>lock(m_pool->m_conditional_mutex);
m_pool->m_conditional_lock.wait(lock);
}
if(!m_pool->m_queueHighThread.empty())
m_pool->m_queueHighThread.try_pop(func);
else if(!m_pool->m_queueThread.empty())
m_pool->m_queueThread.try_pop(func);
if(func)//非空判断
func();
}
}
};
bool m_shutdown;
std::vector<std::thread> m_threads;
ThreadSafeQueue<std::function<void()>> m_queueThread;
ThreadSafeQueue<std::function<void()>> m_queueHighThread;
std::mutex m_conditional_mutex;
std::condition_variable m_conditional_lock;
public:
enum class TaskLevel
{
Normal,
High
};
Queuethreadpool(const int n_threads = 4) :m_threads(std::vector<std::thread>(n_threads)), m_shutdown(false) {}
Queuethreadpool(const Queuethreadpool&) = delete;
Queuethreadpool(Queuethreadpool&&) = delete;
Queuethreadpool& operator=(const Queuethreadpool&) = delete;
Queuethreadpool&& operator=(Queuethreadpool&&) = delete;
void init()//初始化分配线程
{
for (int i = 0; i < m_threads.size(); i++)
{
m_threads.at(i) = std::thread(threadworker(i, this));
}
}
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();
}
}
}
size_t threadcnt() const
{
return m_threads.size();
}
template<typename F, typename... Args>
auto submit(TaskLevel lv,F&& f, Args &&...args)->std::future<decltype(f(args...))>
{
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);//forward为完美转发
auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
std::function<void()>task = [task_ptr]()
{
(*task_ptr)();
};
if(lv== TaskLevel::High)
m_queueHighThread.push(task);
else
m_queueThread.push(task);
m_conditional_lock.notify_one();
return task_ptr->get_future();
}
};
3.使用
int main()
{
Queuethreadpool pool(6);
pool.init();
for (int i = 1; i <= 4; ++i)
for (int j = 1; j <= 5; ++j)
{
pool.submit(Queuethreadpool::TaskLevel::High, [](int a, int b)
{
std::cout << a << " + " << b << " = " << a + b <<"\n" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}, i, j);
}
system("pause");
pool.shutdown();
return 0;
}
输出:
总结
c++11多线程,非常方便。