##错误写法
#include <vector>
#include <string>
#include <functional>
#include <iostream>
#include <future>
#include <thread>
#include <condition_variable>
#include <chrono>
#include <mutex>
#include <queue>
using namespace std;
class ThreadPool {
public:
ThreadPool():m_nthread(2),m_bstop(false){ //默认两个线程
for (int i = 0; i < m_nthread; ++i)
{
m_vecthread.emplace_back([this]() {
while (1)
{
std::function<void()>func;
{
std::unique_lock<std::mutex> lck(m_mtx);
m_cv.wait(lck, [&]() {
return m_quetasks.size() > 0 || m_bstop;
});
if (m_quetasks.size() == 0 && m_bstop)
break;
func = m_quetasks.front();
m_quetasks.pop();
}
func();
}
});
}
}
ThreadPool(int n):m_nthread(n),m_bstop(false){
for (int i = 0; i < m_nthread; ++i)
{
m_vecthread.emplace_back([this]() {
while (1)
{
std::function<void()>func;
{
std::unique_lock<std::mutex> lck(m_mtx);
m_cv.wait(lck, [&]() {
return m_quetasks.size() > 0||m_bstop;//有任务,就算stop了,也要继续将剩下的任务完成
});
if (m_quetasks.size() == 0 && m_bstop)
break;
func = m_quetasks.front();
m_quetasks.pop();
}
func();
}
});
}
}
virtual ~ThreadPool() {
m_bstop = true;
m_cv.notify_all();
for (auto& it : m_vecthread)
{
if (it.joinable())
it.join();
}
}
template<class F,class ...Args>
auto Enqueue(F&& f, Args&& ...args)->std::future<std::_Invoke_result_t<F,Args...>>
{
using return_type = std::_Invoke_result_t<F, Args...>;
std::packaged_task<return_type()> ptask(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<return_type>res = ptask.get_future();
{
std::unique_lock<std::mutex>lck(m_mtx);
if (m_bstop)
throw std::runtime_error("线程池已经停止,不可加入数据");
m_quetasks.emplace([&]() {//!!!错误,当真正调用的时候,
//&保存的早就已经失效了,应当使用指针的形式
ptask();
});
}
m_cv.notify_one();
return res;
}
private:
int m_nthread;
bool m_bstop;
std::queue<std::function<void()>> m_quetasks;
std::vector<std::thread>m_vecthread;
std::condition_variable m_cv;
std::mutex m_mtx;
};
int testPool(int i, int j)
{
return i + j;
}
int main()
{
ThreadPool pool(5);
std::vector<std::future<int>>vecRes;
for (int i = 1; i <= 20; ++i)
{
vecRes.emplace_back(pool.Enqueue(testPool, 0, i));
}
for (auto &&it : vecRes)
{
std::cout<<it.get()<<std::endl;
}
std::cout << "Hello World!\n";
}
//正确写法,使用智能指针,lamda表达式一定要注意生命周期
//尤其是写入vector这种容器内,后面取出来用的这种!!!
#include <vector>
#include <string>
#include <functional>
#include <iostream>
#include <future>
#include <thread>
#include <condition_variable>
#include <chrono>
#include <mutex>
#include <queue>
#include <memory>
using namespace std;
class ThreadPool {
public:
ThreadPool():m_nthread(2),m_bstop(false){ //默认两个线程
for (int i = 0; i < m_nthread; ++i)
{
m_vecthread.emplace_back([this]() {
while (1)
{
std::function<void()>func;
{
std::unique_lock<std::mutex> lck(m_mtx);
m_cv.wait(lck, [&]() {
return m_quetasks.size() > 0 || m_bstop;
});
if (m_quetasks.size() == 0 && m_bstop)
break;
func = m_quetasks.front();
m_quetasks.pop();
}
func();
}
});
}
}
ThreadPool(int n):m_nthread(n),m_bstop(false){
for (int i = 0; i < m_nthread; ++i)
{
m_vecthread.emplace_back([this]() {
while (1)
{
std::function<void()>func;
{
std::unique_lock<std::mutex> lck(m_mtx);
m_cv.wait(lck, [&]() {
return m_quetasks.size() > 0||m_bstop;//有任务,就算stop了,也要继续将剩下的任务完成
});
if (m_quetasks.size() == 0 && m_bstop)
break;
func = m_quetasks.front();
m_quetasks.pop();
}
func();
}
});
}
}
virtual ~ThreadPool() {
m_bstop = true;
m_cv.notify_all();
for (auto& it : m_vecthread)
{
if (it.joinable())
it.join();
}
}
template<class F,class ...Args>
auto Enqueue(F&& f, Args&& ...args)->std::future<std::_Invoke_result_t<F,Args...>>
{
using return_type = std::_Invoke_result_t<F, Args...>;
std::shared_ptr<std::packaged_task<return_type()>> ptask=std::make_shared<std::packaged_task<return_type()>>
(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<return_type>res = ptask->get_future();
{
std::unique_lock<std::mutex>lck(m_mtx);
if (m_bstop)
throw std::runtime_error("线程池已经停止,不可加入数据");
m_quetasks.emplace([ptask]() {
(*ptask)();
});
}
m_cv.notify_one();
return res;
}
private:
int m_nthread;
bool m_bstop;
std::queue<std::function<void()>> m_quetasks;
std::vector<std::thread>m_vecthread;
std::condition_variable m_cv;
std::mutex m_mtx;
};
int testPool(int i, int j)
{
return i + j;
}
int main()
{
ThreadPool pool(5);
std::vector<std::future<int>>vecRes;
for (int i = 1; i <= 20; ++i)
{
vecRes.emplace_back(pool.Enqueue(testPool, 0, i));
}
for (auto &&it : vecRes)
{
std::cout<<it.get()<<std::endl;
}
std::cout << "Hello World!\n";
}
lamda表达式,如果使用值捕获(= or 变量名),就是执行了复制操作创建了一个副本,
如果使用引用,就是对外部变量进行引用。也可以进行移动对象的操作,std::move。
如果需要在lamda表达式中使用不可复制对象,且被删除的对象时,
可以使用智能指针的形式。例如上面的package_task对象,不可复制,可移动(future对象
一样),使用智能指针的形式来调用。