線程池的作用:和內存池一樣,減少內核態與用戶態之間的切換
用C++11新特性實現的超簡版線程池:
#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<future>
#include<queue>
#include<iostream>
class ThreadPool {
public:
std::queue< std::function<void()> > task_queue;
std::vector<std::thread*> threads;
std::mutex mtx;
std::condition_variable cv;
bool isWork = true;
public:
ThreadPool(int size = 5) {
if (size <= 0) return;
for (int i = 0; i < size; ++i) {
threads.push_back( new std::thread(
[=] {
std::function<void()> task;
while (isWork) {
{
std::unique_lock<std::mutex> lock(mtx); //進入臨界區
cv.wait(lock, [this] { return !task_queue.empty(); });
if (task_queue.empty())
continue;
task = task_queue.front(); //獲取任務
task_queue.pop();
} //退出臨界區,鎖自動打開
task(); //任務完成時可執行對象task佔用的內存會自動回收
}
}
));
threads[i]->detach(); //啓動
}
}
template<class F, class... P>
auto insertTask(F &&f, P&&... p)-> std::future<decltype( f(p...) )> {
using taskRetType = decltype( f(p...) ); //獲取F的返回類型
auto pkt_task = std::make_shared< std::packaged_task<taskRetType()> >
( std::bind(std::forward<F>(f), std::forward<P>(p)...) );
std::future<taskRetType> ret = pkt_task->get_future(); //獲取與任務關聯的future
{ //進入臨界區,將任務放入任務隊列
std::unique_lock<std::mutex> lock(mtx);
task_queue.push( [pkt_task]{ (*pkt_task)(); } );
}
cv.notify_one();//喚醒被阻塞線程
return ret;
}
};
成員變量介紹:
名稱 | 類型 | 作用 |
task_queue | std::queue< std::function<void()> > | 一個隊列,隊列的元素爲一個可執行對象;該隊列會被線程池中的所有線程訪問,所以對他的讀寫要加上鎖,寫加鎖是爲了防止數據不一致,讀加鎖是爲了防止同一任務被多個線程執行;同時也應注意在任務執行完成時釋放掉可執行對象佔用的內存 |
threads | std::vector<std::thread*> | 線程池 |
mtx | std::mutex | 互斥量,相當於一把鎖 |
cv | std::condition_variable | 線程同步,喚醒或者沉睡線程 |
如有錯誤,請留言指出感謝!!!