精品国产色欧洲激情_中文字幕在线欧美日韩制服在线_欢迎观看网站影片国产在线观看伊_日本高清一本视频_ww亚洲无码免费在线观看_午夜片无码区观看_欧美性爱福利资源_丰满少妇肥唇翘臀ⅩXX_欧美日韩另类久久_国内揄拍国内精品对白86

編程代碼
新聞詳情

C++11多線(xiàn)程編程(六)——線(xiàn)程池的實(shí)現(xiàn)

發(fā)布時(shí)間:2021-01-06 16:30:00 瀏覽次數(shù):2225

一、為何需要線(xiàn)程池

那么為什么我們需要線(xiàn)程池技術(shù)呢?多線(xiàn)程編程用的好好的,干嘛還要引入線(xiàn)程池這個(gè)東西呢?引入一個(gè)新的技術(shù)肯定不是為了裝酷,肯定是為了解決某個(gè)問(wèn)題的,而服務(wù)端一般都是效率問(wèn)題。

我們可以看到多線(xiàn)程提高了CPU的使用率和程序的工作效率,但是如果有大量的線(xiàn)程,就會(huì)影響性能,因?yàn)橐罅康膭?chuàng)建與銷(xiāo)毀,因?yàn)镃PU需要在它們之間切換。線(xiàn)程池可以想象成一個(gè)池子,它的作用就是讓每一個(gè)線(xiàn)程結(jié)束后,并不會(huì)銷(xiāo)毀,而是放回到線(xiàn)程池中成為空閑狀態(tài),等待下一個(gè)對(duì)象來(lái)使用。

C++11多線(xiàn)程編程(六)——線(xiàn)程池的實(shí)現(xiàn)

二、C++中的線(xiàn)程池

但是讓人遺憾的是,C++并沒(méi)有在語(yǔ)言級(jí)別上支持線(xiàn)程池技術(shù),總感覺(jué)C++委員會(huì)對(duì)多線(xiàn)程的支持像是猶抱琵琶半遮面的羞羞女一樣,無(wú)法完全的放開(kāi)。

雖然無(wú)法從語(yǔ)言級(jí)別上支持,但是我們可以利用條件變量和互斥鎖自己實(shí)現(xiàn)一個(gè)線(xiàn)程池。這里就不得不啰嗦幾句,條件變量和互斥鎖就像兩把利劍,幾乎可以實(shí)現(xiàn)多線(xiàn)程技術(shù)中的大部分問(wèn)題,不管是生產(chǎn)消費(fèi)者模型,還是線(xiàn)程池,亦或是信號(hào)量,所以我們必須好好掌握好這兩個(gè)工具。

#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <condition_variable>
using namespace std;
 
const int MAX_THREADS = 1000; //最大線(xiàn)程數(shù)目
 
template <typename T>
class threadPool
{
public:
    threadPool(int number = 1);
    ~threadPool();
    bool append(T *task);
    //工作線(xiàn)程需要運(yùn)行的函數(shù),不斷的從任務(wù)隊(duì)列中取出并執(zhí)行
    static void *worker(void *arg);
    void run();
 
private:
    //工作線(xiàn)程
    vector<thread> workThread;
    //任務(wù)隊(duì)列
    queue<T *> taskQueue;
    mutex mt;
    condition_variable condition;
    bool stop;
};
 
template <typename T>
threadPool<T>::threadPool(int number) : stop(false)
{
    if (number <= 0 || number > MAX_THREADS)
        throw exception();
    for (int i = 0; i < number; i++)
    {
        cout << "create thread:" << i << endl;
        workThread.emplace_back(worker, this);
    }
}
template <typename T>
inline threadPool<T>::~threadPool()
{
    {
        unique_lock<mutex> unique(mt);
        stop = true;
    }
    condition.notify_all();
    for (auto &wt : workThread)
        wt.join();
}
template <typename T>
bool threadPool<T>::append(T *task)
{
    //往任務(wù)隊(duì)列添加任務(wù)的時(shí)候,要加鎖,因?yàn)檫@是線(xiàn)程池,肯定有很多線(xiàn)程
    unique_lock<mutex> unique(mt);
    taskQueue.push(task);
    unique.unlock();
    //任務(wù)添加完之后,通知阻塞線(xiàn)程過(guò)來(lái)消費(fèi)任務(wù),有點(diǎn)像生產(chǎn)消費(fèi)者模型
    condition.notify_one();
    return true;
}
template <typename T>
void *threadPool<T>::worker(void *arg)
{
    threadPool *pool = (threadPool *)arg;
    pool->run();
    return pool;
}
template <typename T>
void threadPool<T>::run()
{
    while (!stop)
    {
        unique_lock<mutex> unique(this->mt);
        //如果任務(wù)隊(duì)列為空,就停下來(lái)等待喚醒,等待另一個(gè)線(xiàn)程發(fā)來(lái)的喚醒請(qǐng)求
        while (this->taskQueue.empty())
            this->condition.wait(unique);      
        T *task = this->taskQueue.front();
        this->taskQueue.pop();
        if (task)
            task->process();
    }
}
#endif

三、線(xiàn)程池代碼解析

  1. 對(duì)于線(xiàn)程池ThreadPool,必須要有構(gòu)造和析構(gòu)函數(shù),構(gòu)造函數(shù)中,創(chuàng)建N個(gè)線(xiàn)程(這個(gè)自己指定),插入到工作線(xiàn)程當(dāng)中,工作線(xiàn)程可以是vector結(jié)構(gòu)。工作線(xiàn)程中的線(xiàn)程具體要做什么呢?進(jìn)入線(xiàn)程的時(shí)候必要用unique_lock進(jìn)程加鎖處理,不能讓其他線(xiàn)程以及主線(xiàn)程影響到要處理的這個(gè)線(xiàn)程。判斷任務(wù)隊(duì)列是否為空,如果為空,則利用條件變量中的wait函數(shù)來(lái)阻塞該線(xiàn)程,等待任務(wù)隊(duì)列不為空之后喚醒它。然后取出任務(wù)隊(duì)列中的任務(wù),執(zhí)行任務(wù)中的具體操作。
  2. 接著將任務(wù)放入任務(wù)隊(duì)列taskQueue,這里的任務(wù)是外部根據(jù)自己的業(yè)務(wù)自己定義的,可以是對(duì)象,可以是函數(shù),結(jié)構(gòu)體等等,而任務(wù)隊(duì)列這里定義為queue結(jié)構(gòu),一定要記得將任務(wù)放入任務(wù)隊(duì)列的時(shí)候,要在之前加鎖,放入之后再解鎖,這里的加鎖解鎖可以用unique_lock結(jié)構(gòu),當(dāng)然也可以用mutex結(jié)構(gòu),而放入任務(wù)隊(duì)列之后就可以用條件變量的notify_one函數(shù)通知阻塞的線(xiàn)程來(lái)取任務(wù)處理了。
  3. 看過(guò)我之前寫(xiě)的《生產(chǎn)消費(fèi)者模型之條件變量》的朋友對(duì)以上代碼有點(diǎn)熟悉,沒(méi)錯(cuò),線(xiàn)程池的實(shí)現(xiàn)就有點(diǎn)像是生產(chǎn)消費(fèi)者模型,append()就像是生產(chǎn)者,不斷的將任務(wù)放入隊(duì)列,run()函數(shù)就像消費(fèi)者,不斷的從任務(wù)隊(duì)列中取出任務(wù)來(lái)處理,生產(chǎn)消費(fèi)的兩頭分別用notify_one()和wait()來(lái)喚醒和阻塞。更加詳細(xì)的介紹可以去看我的上一篇文章。
  4. 最后寫(xiě)一個(gè)main文件來(lái)調(diào)用線(xiàn)程池的相關(guān)接口,main文件里定義一個(gè)任務(wù)對(duì)象,然后是main函數(shù)。
#include "threadPool.h"
#include <string>
using namespace std;
class Task
{
private:
    int total = 0;
 
public:
    void process();
};
 
//任務(wù)具體實(shí)現(xiàn)什么功能,由這個(gè)函數(shù)實(shí)現(xiàn)
void Task::process()
{
    //這里就輸出一個(gè)字符串
    cout << "task successful! " << endl;
    this_thread::sleep_for(chrono::seconds(1));
}
 
template class std::queue<Task>;
int main(void)
{
    threadPool<Task> pool(1);
    std::string str;
    while (1)
    {
        Task *task = new Task();
        pool.append(task);
        delete task;
    }
}

以上就是線(xiàn)程池的實(shí)現(xiàn)部分,充分利用條件變量和互斥鎖來(lái)實(shí)現(xiàn),模型可以參考生產(chǎn)消費(fèi)者模型。以上代碼部分來(lái)自網(wǎng)絡(luò),根據(jù)自己的需求更改。

在線(xiàn)客服 雙翌客服
客服電話(huà)
  • 0755-23712116
  • 13822267203