使用c 11寫個最簡跨平台執行緒池

2022-03-21 00:13:11 字數 2853 閱讀 6302

為什麼需要多執行緒?

最簡單的多執行緒長啥樣?

為什麼需要執行緒池,有什麼問題?

實現的主要原理是什麼?

帶著這幾個問題,我們依次展開。

1.為什麼需要多執行緒?

大部分程式畢竟都不是計算密集型的,簡單的說,正常情況下,以單執行緒的模式來寫對程式設計師而言是最舒心的。因為所有的**都是順序執行,非常容易理解!函式一級一級往下呼叫,**一行一行執行。但是,**的世界裡,雖然cpu還好,但是卻經常需要用到io資源,或者是其他伺服器的網路資源,比如像資料庫,如果這個時候因此把程序卡住,不管是客戶端還是客戶端都對使用者體驗相當糟糕。當然了,計算密集型的運算就更需要多執行緒,防止主線程被卡住。

2.最簡單的多執行緒長啥樣?

舉個最簡單的例子,伺服器採用阻塞式socket,有乙個網路執行緒負責收發包(io),然後有乙個邏輯主線程負責相應的業務操作,主線程和網路執行緒之間通過最簡單的訊息佇列進行交換,而這個訊息隊例明顯是兩個執行緒都要訪問(輪詢訊息佇列是否為空)到的,所以,我們需要給這個訊息佇列上鎖(std::mutex),即可以解決問題。由於比較簡單我們就不需要看這個怎麼碼了。這種模式雖然簡單,但是在合適的崗位上,也是極好的!

3.那為什麼需要執行緒池呢,有什麼問題?

還以剛才的伺服器舉例,如果業務執行緒邏輯比較複雜,又或者他需要訪問資料庫或者是其他伺服器的資源,讀取檔案等等呢?當然他可以採用非同步的資料庫介面,但是採用非同步意味著業務**被碎片化。非同步是典型的討厭他,但是又幹不掉他的樣子。離題了。回歸。這個時候我們需要多個業務執行緒處理了。多個執行緒就意味著多乙份處理能力!回到上個問題,我們的多執行緒採用輪詢訊息佇列的方式來交換資訊,那麼這麼多個執行緒,不斷的上鎖解鎖,光這個成本就夠了。這個時候,條件變數就上線了(std::condition_variable)就登場了

4.實現的主要原理是什麼?

業務執行緒不要輪詢訊息佇列了,而所有的業務執行緒處於等待狀態,當有訊息再來的時候,再由產生訊息的人,在我們示例場景就是網路執行緒了,隨便喚醒乙個工人執行緒即可。看看最關鍵的**

//消費者

void consumer()

}

算了,還是直接貼完整**,看注釋吧

#ifndef _worker_pool_h_

#define _worker_pool_h_

//file: worker_pool.h

//#define _crt_secure_no_warnings

// g++ -g -std=c++11 1.cc -d_glibcxx_use_nanosleep -lpthread */

#include #include #include #include #include //#include templateclass workerpool

virtual ~workerpool()

void start(workerproc f,int worker_num=1)

proc_ = f;

} //生產者

void push(t *t)

void stop()

mutex_.unlock();

//關閉連線後,等待執行緒自動退出

active_ = false;

cv_.notify_all();

for(threadvec::iterator it = all_thread_.begin();

it != all_thread_.end();++it)

(*it)->join();

}private:

//消費者

void consumer() }

std::mutex mutex_;

std::queuetask_;

std::condition_variable cv_;

bool active_;

std::vector< std::thread* > all_thread_;

workerproc proc_;

};#endif

寫乙個類繼承一下,並寫乙個工作函式和**函式處理

#include "worker_pool.h"

#include //為了多耗點cpu,計算斐波那契數列吧

static int fibonacci(int a)

//非同步計算任務

struct asynccalcquest

//計算需要用到的變數

int num;

int result;

};//為了測試方便,引入全域性變數用於標識執行緒池已將所有計算完成

const int total_count = 1000000;

int now_count = 0;

//繼承一下執行緒池類,在子類處理計算完成的業務,在我們這裡,只是列印一下計算結果

class calcworkerpool:public workerpool

virtual ~calcworkerpool()

//在工人執行緒中執行

void dowork(asynccalcquest *quest)

//在主線程執行

void docallback()

delete quest; //todo:這裡如果採用記憶體池就更好了

callbacks_.pop_back();

} }private:

//這裡是準備給**的任務列表

std::vectorcallbacks_;

std::mutex mutex_callbacks_;

};int main()

while (now_count != total_count)

workers.stop();

return 0;

}

linux完整專案 

C 11執行緒池

執行緒池其實就是把任務佇列和工作執行緒綁到一起,提供乙個向任務佇列中新增任務的介面,下面的 為了表達更加清楚沒有分成標頭檔案和原始檔,僅僅是提供思路。同步機制利用的互斥鎖 條件變數,也可以使用c 11提供的原子數封裝的自旋鎖 條件變數。兩種組合的區別在於,自旋鎖比較適合當任務比較簡單的時候使用,可以...

C 11 執行緒池

根據提出的思路略有改動 已測試 pragma once include include include include include include include include include include include 執行緒池 class threadpool if this task...

c 11 執行緒池系列之一 最簡單的執行緒池

執行緒池最簡單的形式是含有乙個固定數量的工作執行緒來處理任務,典型的數量是std thread hardware concurrency 當有任務要處理時,呼叫乙個函式將任務放到等待佇列中。每個工作執行緒都是從該佇列中取出任務,執行完任務後繼續從等待佇列取出更多的任務來處理。在最簡單的情況,沒有辦法...