詳解C 17執行緒池的實現

2021-09-14 02:28:28 字數 2477 閱讀 1188

首先介紹下類的宣告

class threadpool

;

threadpool中只有三個函式,建構函式,析構函式以及乙個enqueue(push任務佇列的函式)。

這些宣告看上去平淡無奇,但看到decltype(auto)是不是有些懵?如果你不熟悉c++14可能是不會明白這是個啥東西。decltype是用來推導型別的,和auto有什麼區別呢?decltype需要乙個引數來推導型別,是依葫蘆畫瓢進行推導的,比如以下例子

int  x = 1;

int& rx = x;

decltype(x) y = 2; //x 是int

decltype(rx) ry = y; //ry 是int&

auto的推導是比較複雜的推導,有點類似於模板的推導(除大括號初始化推導外都是相同的),會進行引用摺疊(這裡不再贅述,《effective modern c++》有詳細的篇幅介紹)。decltype(auto)的意思就是用decltype的推導規則,來推導auto的型別,在這裡可以獲取到任務的返回值型別,在具體enqueue函式再說。

先介紹建構函式,**實現如下圖。

inline threadpool::threadpool(size_t size) :stop(false)

); //條件變數的wait函式 防止虛假喚醒

if (this->stop && this->tasks.empty())

task = std::move(this->tasks.front()); //將佇列的頭部移動給task

this->tasks.pop(); //記得出佇列

//臨界區結束 自動釋放鎖 mutex_

}task(); //執行任務

}});

}}

由於是在標頭檔案定義的建構函式實體,因此用了inline標記(不然會報重複定義錯誤),其實這裡可以在cpp檔案實現,這樣就可以不用inline,想一想為什麼enqueue可以不用inline?在函式體中用whlile(true)迴圈等待任務的到來或者是執行緒池的析構(vs2013可能會有警告,可以換成for(;;))。迴圈內是取佇列頭執行。**中已經詳細注釋。

析構函式實現**如下

inline threadpool::~threadpool()

cond_.notify_all();//通知所有的執行緒退出迴圈

for_each(workers.begin(), workers.end(), std::mem_fn(&std::thread::join)); //等待

}

析構函式就是一些收尾工作,通知執行緒池裡所有的執行緒準備析構,停止任務進佇列,阻塞到所有的任務完成。

下面就是enqueue的實現

//原來的函式是用返回值尾序來獲取型別 在c++14之後支援decltype(auto)進行型別的推導(不熟悉decltype推導規則可以看看effective modern c++)

templatedecltype(auto) threadpool::enqueue(f&& f, args && ...args)

); }

cond_.notify_one(); //通知任意乙個執行緒接收任務

return res;

}

不熟悉可變模板引數,可以自行搜尋相關知識。result_of_t獲取到返回值型別,bind將函式和引數進行繫結,packaged_task用來包裝成非同步的函式,返回乙個shared_ptr。這裡介紹下,如果是c++11的話,那麼

decltype(auto) threadpool::enqueue(f&& f, args && ...args)
應該換成如下

auto threadpool::enqueue(f&& f, args&&... args) 

-> std::future::type>

或者是 

auto threadpool::enqueue(f&& f, args&&... args) 

-> std::future>

前面介紹過了,這種叫返回值類別尾序語法。到這裡乙個簡單的執行緒池就完成了,你可以愉快地進行多執行緒玩耍了。運用起來非常簡單,樣例在github上有,你可以去看看。

對了,前文中提到為什麼enqueue為什麼可以不用inline呢?應該是成員函式是模板函式的原因,模板函式並非在定義時例項化,而在呼叫處例項化,這並不違反odr原則(一處定義原則)。具體的例項化點(poi),是呼叫模板函式後,模板類和模板函式的例項化點並不一樣,模板類在呼叫前,模板函式在呼叫後,例項化點並非真正例項化,通常真正的例項化會在翻譯單元末尾處,詳見《c++ template》的10.3節。(如果是錯誤的,希望大神能解釋下)

其他:c++20出來了,modules和coroutines、約束新特性看起來有些意思,最近在看c++的協程,有空的也會寫個協程的實現。

c 執行緒池的實現

github 傳送門 1.使用例項 測試job寫檔案 class job public wjob job job 1 void run endif 3.wthread 對wthread的封裝,主要在於將之與wjob繫結以完成任務,並與執行緒池繫結,在任務結束後將自己放回空閒佇列 每乙個執行緒都執行r...

執行緒池的c 實現

emmmm,寫這個的主要目的是為了加深對互斥鎖和條件變數的理解,只看unix網路程式設計不實踐一下老覺得心裡沒點底,正好這個東西能練一下而且面試好像也有問到,就手動實現了一下 執行緒池運用的設計模式是命令模式,其原理基本上都能查到這裡就不多說了 直接上 好了 首先是任務類 task.h ifndef...

C 執行緒池的實現

寫了乙個簡易執行緒池,原理簡單介紹下,就是設定乙個任務佇列queue,用來放要執行的函式,還有乙個執行緒陣列vector,用來存放所有的執行緒。執行緒建立以後就存放在相應的vector裡,空閒的執行緒去queue裡去取要執行的函式位址,在run函式中執行,假如乙個執行緒的run函式執行好後,發現佇列...