前言
在很多公司小組都需要使用會議室進行讨論,但是每個小組都配備一個會議室又會很浪費。是以就将所有的會議室都拿出來放到一起,那個小組需要就像行政部門申請即可,根據申請的先後順序使用會議室。使用完成以後自動歸還,無需派專人進行管理。
基于這一思路,我們也可以把線程資源放到一個區域,然後根據每個使用者的需求配置設定線程資源。并且還可以實作自動化的線程資源配置設定。
設計線程池有幾個關鍵的問題:第一,線程中應該建立幾個工作線程;第二,是否應該等待線程執行結束…
第一個線程
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSPJR1T0kleONTRq1ENj1mYsJlMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1MDN0UzN0AjMzIzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
submit
不斷送出任務,然後threads擷取其中任務然後執行。這就是線程池的主要執行原理。
#include <thread>
#include <atomic>
#include <queue>
#include <vector>
#include <iostream>
class join_threads
{
std::vector<std::thread> &threads;
public:
explicit join_threads(std::vector<std::thread> &threads_):threads(threads_){}
~join_threads()
{
for(unsigned long i = 0 ; i < threads.size();++i)
{
if(threads[i].joinable())
threads[i].join();
}
}
};
class thread_pool {
std::atomic_bool done;
std::queue<std::function<void()> > work_queue;
std::vector<std::thread> threads;
join_threads joiner;
void work_thread() {
while (!done) {
std::function<void()> task;
task = work_queue.front();
work_queue.pop();
if (task) {
task();
} else {
std::this_thread::yield();
}
}
}
public:
thread_pool() : done(false), joiner(threads) {
unsigned const thread_count = std::thread::hardware_concurrency();
try {
for (unsigned i = 0; i < thread_count; ++i) {
threads.push_back(std::thread(&thread_pool::work_thread, this));
}
} catch (...) {
done = true;
throw;
}
}
~thread_pool() {
done = true;
}
template<typename FunctionType>
void submit(FunctionType f) {
work_queue.push(std::function<void() >(f));
}
};
void fun() {
std::cout << "hello world" << std::endl;
}
int main() {
thread_pool pool;
// std::cout << "123";
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.submit(fun);
pool.work_thread();
}
這就是簡單實作的線程池,通過
submit()
送出資料,調用
work_thread()
函數執行。
這就類似每天晚上小組送出第二天會議室申請表,然後到了第二天直接配置設定會議室使用權。這樣就可以實作,例如在一些搶票或者需要快速反應的多線程情況下,就可以使用線程池。
thread_pool() : done(false), joiner(threads) {
unsigned const thread_count = std::thread::hardware_concurrency();
try {
for (unsigned i = 0; i < thread_count; ++i) {
threads.push_back(std::thread(&thread_pool::work_thread, this));
}
} catch (...) {
done = true;
throw;
}
}
根據目前的處理的線程數,建立線程,将這一線程放入到
threads
容器中。利用
done
訓示是否線程池完成操作,當
done
為false時,暫未完成線程池,為true時則完成線程池。
void work_thread() {
while (!done) {
std::function<void()> task;
task = work_queue.front();
work_queue.pop();
if (task) {
task();
} else {
std::this_thread::yield();
}
}
}
work_thread()
從隊列中取出待執行的函數,然後執行函數。
但是上面這個函數我也不知道為什麼始終沒辦法編譯通過,可以去看這位同僚的部落格。
如果大家能夠告訴我我的代碼那個地方存在問題我将萬分感謝!
避免乒乓緩存
每次線程調用
submit
時,會向共享隊列添加一個新元素,類似的工作線程會不停的從隊列中取出元素來執行,這意味着處理器數目的增加會導緻工作隊列競争。
避免的方法主要就是給每一個線程都使用一個單獨的工作隊列,将任務放到自己的隊列中。
總結
這一部分内容主要需要動手實作,雖然在很多語言中線程池已經寫成子產品直接調用執行了。但是還是要知道其中的原理,以免在面試中遇到這樣的問題,搞得瓜兮兮的!