在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    「Linux學(xué)習(xí)」高并發(fā)服務(wù)器框架 線程池介紹+線程池封裝

    「Linux學(xué)習(xí)」高并發(fā)服務(wù)器框架 線程池介紹+線程池封裝

    目錄

    前言

    本文主要學(xué)習(xí) Linux內(nèi)核編程 ,結(jié)合 Visual Studio 2019 進行跨平臺編程,內(nèi)容包括線程池介紹以及線程池封裝

    一、線程池介紹

    線程池基本概念

    • 線程池 是預(yù)先創(chuàng)建線程的一種技術(shù) (服務(wù)器真正意義上實現(xiàn)高并發(fā)就必須用線程池)
    • 舉個例子:生活中的水池,是裝東西的容器,用來裝水的,線程池當(dāng)然就是拿來裝線程的
    • 線程池在任務(wù)還沒有到來之前,創(chuàng)建一定數(shù)量的線程,放入空閑隊列中,這些線程都是處于阻塞狀態(tài),不消耗CPU,但占用較小的內(nèi)存空間
    • 當(dāng)新任務(wù)到來時,緩沖池選擇一個空閑線程,把任務(wù)傳入此線程中運行,如果緩沖池已經(jīng)沒有空閑線程,則新建若干個線程,當(dāng)系統(tǒng)比較空閑時,大部分線程都一直處于暫停狀態(tài),線程池自動銷毀一部分線程,回收系統(tǒng)資源

    線程池組成部分

    • 線程池類

    維護工作者線程隊列(包括空閑與忙碌隊列)

    維護一個任務(wù)隊列

    維護一個線程池調(diào)度器指針

    • 線程池調(diào)度器 (本身也是一個線程)

    負責(zé)線程調(diào)度

    負責(zé)任務(wù)分配

    • 工作者線程類 (線程池中的線程類的封裝)
    • 任務(wù)隊列
    • 任務(wù)接口 (實際的業(yè)務(wù)邏輯都繼承自該接口)

    線程池工作原理

    根據(jù)服務(wù)器的需要,來設(shè)置線程的數(shù)量,可能是10條、20條、30條,根據(jù)服務(wù)器的承載,10條不代表只能做10個任務(wù),總有任務(wù)做的快,有的做的慢,可能可以完成20個任務(wù)

    舉個例子:如上動圖所示,當(dāng)我們服務(wù)器收到一個注冊業(yè)務(wù),是一個服務(wù)器要執(zhí)行的任務(wù),它會進入到任務(wù)隊列,隊列先進先出,順次執(zhí)行,任務(wù)會喚醒空閑列表當(dāng)中的一個空閑的線程,接到任務(wù)之后,空閑線程會從空閑列表中消失,進入到忙碌列表,去完成對應(yīng)的任務(wù),完成任務(wù)后,從忙碌列表中出去,到空閑列表繼續(xù)等待新任務(wù)

    如果,所有的線程都在忙,都在做任務(wù),這時候登錄進來,先進入任務(wù)隊列,會創(chuàng)建一個新的線程來接這個任務(wù),當(dāng)所有線程都完成任務(wù),回到空閑列表后,新創(chuàng)建的線程銷毀,留下原先設(shè)置的對應(yīng)數(shù)量線程(類似,保留老員工,把實習(xí)生裁員)

    • 隊列: 先進先出
    • 空閑列表(鏈表): 不定長(有的時候可能需要創(chuàng)建新線程來接任務(wù))
    • 忙碌列表(鏈表): 不定長(有的時候可能需要創(chuàng)建新線程來接任務(wù))

    話不多說,咱們上號,封裝一下線程池相關(guān)函數(shù),來進行測試

    二、線程池代碼封裝

    main.cpp

    • 主函數(shù),設(shè)置10條線程,來執(zhí)行30個任務(wù)

    #include #include #include “ThreadPool.h”#include “ChildTask.h”using namespace std;int main(){ThreadPool* pool = new ThreadPool(10);//10條線程for (int i = 0; i pushTask(task);}while (1) {}return 0;}

    ThreadPool.h

    • 對線程池進行設(shè)計,核心包括 最大、最小線程數(shù) , 忙碌列表 , 空閑列表 , 任務(wù)隊列 , 互斥量 , 條件變量 ,以及 線程執(zhí)行函數(shù)

    #pragma once#include //隊列#include //鏈表頭文件#include //線程頭文件#include //find查找#include #include “BaseTask.h”using namespace std;#define MIN_NUM 10//最小值 默認參數(shù)class ThreadPool{public:ThreadPool(const int num = MIN_NUM);~ThreadPool();//判斷任務(wù)隊列是否為空bool QueueIsEmpty();//線程互斥量加鎖解鎖void Lock();void Unlock();//線程條件變量等待和喚醒void Wait();void WakeUp();//添加任務(wù)到任務(wù)隊列void pushTask(BaseTask* task);//從任務(wù)隊列移除任務(wù)BaseTask* popTask(BaseTask* task);//從忙碌回到空閑 工作結(jié)束void MoveToIdle(pthread_t id);//從空閑到忙碌 工作開始void MoveToBusy(pthread_t id);//線程執(zhí)行函數(shù)static void* RunTime(void* vo);private:int threadMinNum;//最大線程數(shù)量int threadMaxNum;//最小線程數(shù)量queuetaskQueue;//任務(wù)隊列l(wèi)istbusyList;//線程忙碌列表listidleList;//線程空閑列表pthread_mutex_t mutex;//互斥量:做鎖pthread_cond_t cond;//條件變量:讓線程等待或者喚醒};

    ThreadPool.cpp

    • 對函數(shù)進行參數(shù)的設(shè)置,核心在于線程執(zhí)行函數(shù)上的設(shè)置,在工作前和工作完設(shè)置打印,方便我們進行觀察

    #include “ThreadPool.h”ThreadPool::ThreadPool(const int num){this->threadMinNum = num;//條件變量、互斥量初始化pthread_mutex_init(&this->mutex, NULL);pthread_cond_init(&this->cond, NULL);pthread_t id;//線程num條創(chuàng)建for (int i = 0; i threadMinNum; i++){//線程創(chuàng)建pthread_create(&id, NULL, RunTime, this);this->idleList.push_back(id);//線程存入空閑列表}}ThreadPool::~ThreadPool(){}//任務(wù)隊列是否為空bool ThreadPool::QueueIsEmpty(){return this->taskQueue.empty();}//線程加鎖void ThreadPool::Lock(){pthread_mutex_lock(&this->mutex);}//線程解鎖void ThreadPool::Unlock(){pthread_mutex_unlock(&this->mutex);}//線程等待void ThreadPool::Wait(){pthread_cond_wait(&this->cond, &this->mutex);}//線程喚醒void ThreadPool::WakeUp(){pthread_cond_signal(&this->cond);}//添加任務(wù)到任務(wù)隊列void ThreadPool::pushTask(BaseTask* task){Lock();taskQueue.push(task);Unlock();WakeUp();}//從任務(wù)隊列移除任務(wù)BaseTask* ThreadPool::popTask(BaseTask* task){task = this->taskQueue.front();//從隊列頭取this->taskQueue.pop();//刪除隊列頭return task;}//從忙碌回到空閑 工作結(jié)束void ThreadPool::MoveToIdle(pthread_t id){list::iterator iter;iter = find(busyList.begin(), busyList.end(), id);if (iter != busyList.end()){//從忙碌移除this->busyList.erase(iter);//添加到空閑this->idleList.push_back(*iter);//this->idleList.push_back(id)}}//從空閑到忙碌 工作開始void ThreadPool::MoveToBusy(pthread_t id){list::iterator iter;iter = find(idleList.begin(), idleList.end(), id);if (iter != idleList.end()){//從空閑移除this->idleList.erase(iter);//添加到忙碌this->busyList.push_back(*iter);//this->idleList.push_back(id)}}//線程執(zhí)行函數(shù)void* ThreadPool::RunTime(void* vo){//拿到執(zhí)行線程自己的id 因為后面要處理忙碌和空閑的情況pthread_t id = pthread_self();//確保主線程與子線程分離,子線程結(jié)束后,資源自動回收pthread_detach(id);//線程參數(shù)獲取ThreadPool* argThis = (ThreadPool*)vo;while (true){argThis->Lock();//如果任務(wù)隊列為空 線程則一直等待 //知道任務(wù)隊列不為空則會被pushTask函數(shù)喚醒線程while (argThis->QueueIsEmpty()){argThis->Wait();}argThis->MoveToBusy(id);cout << "工作前 任務(wù)數(shù):" <taskQueue.size() << endl;cout << "工作前 busy:" <busyList.size() << endl;cout << "工作前 idle:" <idleList.size() << endl;cout << "———————————————–" Unlock();//任務(wù)工作task->working();//工作結(jié)束argThis->Lock();argThis->MoveToIdle(id);argThis->Unlock();cout << "工作完 任務(wù)數(shù):" <taskQueue.size() << endl;cout << "工作完 busy:" <busyList.size() << endl;cout << "工作完 idle:" <idleList.size() << endl;cout >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>” << endl;}return nullptr;}

    ChildTask.h

    • 子類配置

    #pragma once#include “BaseTask.h”#include #include //sleep頭文件using namespace std;class ChildTask :public BaseTask{public:ChildTask(char* data);~ChildTask();void working();};

    ChildTask.cpp

    • 子類設(shè)置延時模擬做任務(wù)的時間比較長

    #include “ChildTask.h”ChildTask::ChildTask(char* data) :BaseTask(data)//參數(shù)傳給父類{}ChildTask::~ChildTask(){}void ChildTask::working(){cout <data << "正在執(zhí)行……" << endl;sleep(3);//延時3秒 (模擬做業(yè)務(wù)的時間比較長)}

    BaseTask.h

    • 基類設(shè)置結(jié)構(gòu)體來裝業(yè)務(wù)

    #pragma once#include class BaseTask{public:BaseTask(char* data);~BaseTask();char data[1024]; //裝業(yè)務(wù)virtual void working() = 0;//虛函數(shù)};

    BaseTask.cpp

    • 基類配置

    #include “BaseTask.h”BaseTask::BaseTask(char* data){bzero(this->data, sizeof(this->data));//清空memcpy(this->data, data, sizeof(data));}BaseTask::~BaseTask(){delete this->data;//清除釋放}

    三、測試效果

    • 通過Linux連接VS進行跨平臺編程,我們可以清晰的看到有幾個線程是在做任務(wù),幾個線程是空閑的,整個過程就很清晰直觀的展現(xiàn)出來了,如下動圖所示:
    • 10條線程做30個任務(wù)的全部記錄,如下如所示:

    四、總結(jié)

    創(chuàng)建線程池的好處

    • 線程池的使用,能讓我們搭建的高并發(fā)服務(wù)器真正意義上做到高并發(fā)
    • 降低資源消耗

    通過重復(fù)利用自己創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗

    • 提高響應(yīng)速度

    當(dāng)任務(wù)到達時,任務(wù)可以不需要等待線程創(chuàng)建和銷毀就能立即執(zhí)行

    • 提高線程的可管理性

    線程式稀缺資源,如果無限的創(chuàng)建線程,不僅會消耗資源,還會降低系統(tǒng)的穩(wěn)定性

    使用線程池可以進行統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年8月16日 09:35
    下一篇 2022年8月16日 09:35

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息