国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵

這篇具有很好參考價值的文章主要介紹了Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵,Linux練功 初階功法,linux,運(yùn)維,設(shè)計模式,單例模式,服務(wù)器

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???慕斯主頁修仙—別有洞天

?? ????????????????????????????????????????? ???今日夜電波:マイノリティ脈絡(luò)—ずっと真夜中でいいのに。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0:24━━━━━━???──────── 4:02
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????? ? ?? ? ? ? ?? ? ????

????????????????????????????????????????關(guān)注??點(diǎn)贊??收藏您的每一次鼓勵都是對我莫大的支持??


?

目錄

日志

認(rèn)識ctime

如何遍歷可變參數(shù)列表

日志的實現(xiàn)

線程池

線程池的理解

線程池的實現(xiàn)

使用單例模式改造線程池

單例模式的理解

單例模式的實現(xiàn)


日志

認(rèn)識ctime

? ? ctime 是 C/C++ 中的一個庫,主要用于處理日期和時間。它包含了一系列函數(shù),用于獲取系統(tǒng)當(dāng)前時間、進(jìn)行時間格式化輸出、以及字符串和日期之間的轉(zhuǎn)換等。下面是一些常用的 ctime 函數(shù)及其詳解:

????????time_t

????????time_t 是 C/C++ 語言中用于表示時間的一個數(shù)據(jù)類型,通常是一個長整型(long int 或 long long int)。它用來存儲從 1970 年 1 月 1 日 00:00:00(UTC,即協(xié)調(diào)世界時)起至今的秒數(shù),這個起始時間點(diǎn)被稱為 Unix 時間戳的紀(jì)元(epoch)。

  1. time() 函數(shù)
    • 函數(shù)原型:time_t time(time_t *tloc)
    • 功能:返回從紀(jì)元(即格林尼治時間(GMT)1970年1月1日午夜0點(diǎn))開始至今的秒數(shù)。如果 tloc 不是一個空指針,time 函數(shù)還會將返回值寫入 tloc 所指向的位置。
    • 返回值:一個 time_t 類型的值,表示自紀(jì)元以來的秒數(shù)。
  1. localtime() 函數(shù)
    • 函數(shù)原型:struct tm *localtime(const time_t *timeptr)
    • 功能:將 time_t 類型的時間戳轉(zhuǎn)換為本地時間的 tm 結(jié)構(gòu)體。
    • 返回值:一個指向 tm 結(jié)構(gòu)體的指針,包含了轉(zhuǎn)換后的本地時間信息。
  1. gmtime() 函數(shù)
    • 函數(shù)原型:struct tm *gmtime(const time_t *timeptr)
    • 功能:將 time_t 類型的時間戳轉(zhuǎn)換為協(xié)調(diào)世界時(UTC)的 tm 結(jié)構(gòu)體。
    • 返回值:一個指向 tm 結(jié)構(gòu)體的指針,包含了轉(zhuǎn)換后的 UTC 時間信息。
  1. asctime() 函數(shù)
    • 函數(shù)原型:char *asctime(const struct tm *timeptr)
    • 功能:將 tm 日期時間結(jié)構(gòu)體轉(zhuǎn)換成日期時間字符串。
    • 返回值:指向日期時間字符串的指針。
  1. ctime() 函數(shù)
    • 函數(shù)原型:char *ctime(const time_t *timeval)
    • 功能:將 time_t 秒數(shù)日期時間格式直接轉(zhuǎn)換成日期時間字符串格式輸出。使用更加方便,因為不需要先轉(zhuǎn)換為 tm 結(jié)構(gòu)體。
    • 返回值:指向日期時間字符串的指針。如果返回的時間在1970年1月1日 0:0:0(UTC時間)之前,則返回NULL。

????????struct tm

? ? struct tm 是 C/C++ 語言中的一個結(jié)構(gòu)體,用于表示和處理日期和時間。它的具體結(jié)構(gòu)如下:

struct tm {
    int tm_sec;   // 秒,范圍從 0 到 59
    int tm_min;   // 分,范圍從 0 到 59
    int tm_hour;  // 時,范圍從 0 到 23
    int tm_mday;  // 一個月中的日,范圍從 1 到 31
    int tm_mon;   // 月份,范圍從 0 到 11(其中0表示一月,11表示十二月)
    int tm_year;  // 自1900年起的年數(shù)
    int tm_wday;  // 一周中的日,范圍從 0(周日)到 6(周六)
    int tm_yday;  // 一年中的日,范圍從 0 到 365
    int tm_isdst; // 夏令時標(biāo)識符,小于0表示沒有夏令時,等于0表示不知道,大于0表示夏令時
};

????????這個結(jié)構(gòu)體包含了年、月、日、時、分、秒等時間信息,使得開發(fā)者能夠方便地獲取和處理當(dāng)前時間、進(jìn)行日期和時間的計算、格式化輸出等操作。

????????在編程中,你可以使用 time() 函數(shù)獲取當(dāng)前時間的時間戳(以秒為單位),然后使用 localtime()gmtime() 函數(shù)將這個時間戳轉(zhuǎn)換為 struct tm 結(jié)構(gòu)體,從而獲取詳細(xì)的日期和時間信息。

????????因此如果我們要讓日志獲得具體的時間并且打印出來可以寫出如下函數(shù):

    std::string TimeStampExLocalTime()
    {
        time_t currtime=time(nullptr);
        struct tm*curr=localtime(&currtime);
        char time_buffer[128];
        snprintf(time_buffer,sizeof(time_buffer),"%d-%d-%d %d:%d:%d",curr->tm_year+1900,curr->tm_mon+1,curr->tm_mday,curr->tm_hour,curr->tm_min,curr->tm_sec);
        return time_buffer;
    }

如何遍歷可變參數(shù)列表

????????在C語言中,遍歷可變參數(shù)列表通常需要使用va_list、va_startva_argva_end這四個宏。這些宏在stdarg.h頭文件中定義,允許你在函數(shù)中處理可變數(shù)量的參數(shù)。

????????以下是一個簡單的步驟說明如何遍歷可變參數(shù)列表:

  1. 定義函數(shù)原型:在函數(shù)原型中使用...來表示可變參數(shù)列表。
  2. 初始化va_list:在函數(shù)內(nèi)部,使用va_start宏來初始化一個va_list類型的變量。va_start的第一個參數(shù)是你的va_list變量,第二個參數(shù)是可變參數(shù)列表之前的最后一個固定參數(shù)。
  3. 遍歷參數(shù):使用va_arg宏來遍歷參數(shù)列表。每次調(diào)用va_arg時,它都會返回列表中的下一個參數(shù),并將va_list指針向前移動到下一個參數(shù)。你需要指定返回參數(shù)的類型。
  4. 結(jié)束遍歷:在遍歷完所有參數(shù)后,使用va_end宏來清理va_list變量。

????????下面是一個示例函數(shù),它接受一個整數(shù)作為參數(shù)數(shù)量,然后遍歷可變參數(shù)列表中的所有整數(shù),并將它們打印出來:

#include <stdarg.h>
#include <stdio.h>

void print_numbers(int count, ...) {
    va_list args;
    int i;

    // 初始化va_list變量
    va_start(args, count);

    // 遍歷參數(shù)列表
    for (i = 0; i < count; i++) {
        int number = va_arg(args, int); // 獲取下一個int類型的參數(shù)
        printf("%d ", number); // 打印參數(shù)
    }

    // 清理va_list變量
    va_end(args);

    printf("\n");
}

int main() {
    print_numbers(3, 1, 2, 3); // 輸出: 1 2 3
    print_numbers(5, 5, 10, 15, 20, 25); // 輸出: 5 10 15 20 25
    return 0;
}

????????在上面的代碼中,print_numbers函數(shù)首先使用va_start初始化va_list變量args。然后,它通過一個循環(huán)使用va_arg宏來遍歷參數(shù)列表,并在每次迭代中打印一個整數(shù)。最后,它使用va_end來清理va_list變量。

????????請注意,由于C語言在編譯時不會檢查可變參數(shù)的類型或數(shù)量,因此在使用可變參數(shù)時應(yīng)該格外小心,以避免類型不匹配或緩沖區(qū)溢出等問題。此外,確保傳遞給va_start的最后一個固定參數(shù)是正確的,因為va_start使用這個參數(shù)來確定可變參數(shù)列表的起始位置。

日志的實現(xiàn)

#pragma once

#include <iostream>
#include <fstream>
#include <string>
#include <cstdarg>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

enum
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};

enum
{
    Screen = 10,
    OneFile,
    ClassFile
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case Debug:
        return "Debug";
    case Info:
        return "Info";
    case Warning:
        return "Warning";
    case Error:
        return "Error";
    case Fatal:
        return "Fatal";
    default:
        return "Unknown";
    }
}

const int defaultstyle = Screen;
const std::string default_filename = "log.";
const std::string logdir = "log";

class Log
{
public:
    Log() : style(defaultstyle), filename(default_filename)
    {
        mkdir(logdir.c_str(), 0775);
    }
    void Enable(int sty) //
    {
        style = sty;
    }
    std::string TimeStampExLocalTime()
    {
        time_t currtime = time(nullptr);
        struct tm *curr = localtime(&currtime);
        char time_buffer[128];
        snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
                 curr->tm_year + 1900, curr->tm_mon + 1, curr->tm_mday,
                 curr->tm_hour, curr->tm_min, curr->tm_sec);
        return time_buffer;
    }
    void WriteLogToOneFile(const std::string &logname, const std::string &message)
    {
        umask(0);
        int fd = open(logname.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0666);
        if(fd < 0) return;
        write(fd, message.c_str(), message.size());
        close(fd);
        // std::ofstream out(logname);
        // if (!out.is_open())
        //     return;
        // out.write(message.c_str(), message.size());
        // out.close();
    }
    void WriteLogToClassFile(const std::string &levelstr, const std::string &message)
    {
        std::string logname = logdir;
        logname += "/";
        logname += filename;
        logname += levelstr;
        WriteLogToOneFile(logname, message);
    }

    void WriteLog(const std::string &levelstr, const std::string &message)
    {
        switch (style)
        {
        case Screen:
            std::cout << message;
            break;
        case OneFile:
            WriteLogToClassFile("all", message);
            break;
        case ClassFile:
            WriteLogToClassFile(levelstr, message);
            break;
        default:
            break;
        }
    }
    void LogMessage(int level, const char *format, ...) // 類C的一個日志接口
    {
        char leftbuffer[1024];
        std::string levelstr = LevelToString(level);
        std::string currtime = TimeStampExLocalTime();
        std::string idstr = std::to_string(getpid());

        char rightbuffer[1024];
        va_list args; // char *, void *
        va_start(args, format);
        // args 指向了可變參數(shù)部分
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, args);
        va_end(args); // args = nullptr;
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%s][%s] ",
                 levelstr.c_str(), currtime.c_str(), idstr.c_str());

        std::string loginfo = leftbuffer;
        loginfo += rightbuffer;
        WriteLog(levelstr, loginfo);
    }
    // void operator()(int level, const char *format, ...)
    // {
    //     LogMessage(int level, const char *format, ...)
    // }
    ~Log() {}

private:
    int style;
    std::string filename;
};

Log lg;

class Conf
{
public:
    Conf()
    {
        lg.Enable(Screen);
    }
    ~Conf()
    {}
};

Conf conf;

線程池

線程池的理解

????????在Linux環(huán)境下,線程池是一種用于管理和復(fù)用線程的技術(shù),旨在避免頻繁地創(chuàng)建和銷毀線程,從而提高系統(tǒng)的性能和資源利用率。線程池預(yù)先創(chuàng)建并維護(hù)一定數(shù)量的線程,這些線程在空閑時處于等待狀態(tài),當(dāng)任務(wù)到來時,線程池會分配一個空閑線程來執(zhí)行任務(wù),任務(wù)完成后線程再次回到空閑狀態(tài),等待下一個任務(wù)的分配。

????????線程池的主要組件包括任務(wù)隊列和線程池管理器。任務(wù)隊列用于存放待執(zhí)行的任務(wù),線程池管理器則負(fù)責(zé)線程的創(chuàng)建、銷毀、調(diào)度和管理。線程池的大小可以根據(jù)實際需求進(jìn)行調(diào)整,以達(dá)到最佳的性能和資源利用率。

????????線程池在Linux下的應(yīng)用場景非常廣泛,尤其適用于需要處理大量并發(fā)任務(wù)或突發(fā)請求的情況。例如,Web服務(wù)器在處理大量用戶請求時,可以使用線程池來管理和復(fù)用線程,提高系統(tǒng)的響應(yīng)速度和吞吐量。此外,線程池還可以用于異步任務(wù)執(zhí)行、定時任務(wù)調(diào)度等場景。

????????總的來說,Linux下的線程池是一種高效、靈活的并發(fā)編程技術(shù),能夠降低系統(tǒng)資源消耗、提高系統(tǒng)性能,并方便對線程并發(fā)數(shù)進(jìn)行管控。通過合理使用線程池,可以顯著提升Linux系統(tǒng)的穩(wěn)定性和可擴(kuò)展性。

線程池的實現(xiàn)

????????實際上線程池的實現(xiàn)同生產(chǎn)者消費(fèi)者模型之間是存在密切的關(guān)系的:

  1. 線程池為生產(chǎn)者消費(fèi)者模型提供了線程管理和復(fù)用的機(jī)制,使得生產(chǎn)者和消費(fèi)者能夠并發(fā)地執(zhí)行任務(wù),提高了系統(tǒng)的并發(fā)性能。
  2. 生產(chǎn)者可以將生成的數(shù)據(jù)或任務(wù)提交給線程池,由線程池中的線程負(fù)責(zé)執(zhí)行,實現(xiàn)了任務(wù)的異步處理。我們可以讓多個生產(chǎn)者向線程池推送任務(wù),提高推送任務(wù)的效率。
  3. 消費(fèi)者可以從線程池中獲取線程來處理從緩沖區(qū)中取出的數(shù)據(jù)或任務(wù),確保了消費(fèi)者的處理速度與生產(chǎn)者的生成速度相匹配,避免了資源的浪費(fèi)??梢院侠淼呐渲镁€程池中的線程來提高線程池的處理效率。

????????線程池實現(xiàn)的大致圖示如下:

Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵,Linux練功 初階功法,linux,運(yùn)維,設(shè)計模式,單例模式,服務(wù)器?

????????實現(xiàn)如下(詳細(xì)請看代碼,已給出詳細(xì)的注釋,復(fù)用了之前文章的代碼):

#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

static const int defaultnum = 5;//默認(rèn)的處理任務(wù)的線程數(shù)量

class ThreadData  //用于傳輸線程的數(shù)據(jù),這里就先傳輸一個線程名
{
public:
    ThreadData(const std::string &name) : threadname(name)
    {
    }

public:
    std::string threadname;
};

template <class T>
class ThreadPool
{
    public:
    ThreadPool(int thread_num=defaultnum):_thread_num(thread_num) //構(gòu)造線程池,可以指定處理任務(wù)的線程數(shù)量
    {
        pthread_mutex_init(&_mutex, nullptr); //初始化鎖和條件變量
        pthread_cond_init(&_cond, nullptr);

        for(int i=0;i<_thread_num;i++) //創(chuàng)建線程,這里我們引用了之前寫的線程接口:Thread(const std::string &threadname, func_t<T> func, T &data)
        {
            std::string threadname ="thread-"; //構(gòu)建線程名
            threadname+=std::to_string(i+1);
            ThreadData td(threadname); //線程要傳入的數(shù)據(jù)

            _threads.emplace_back(threadname,std::bind(&ThreadPool<T>::ThreadRun,this,std::placeholders::_1),td); //std::vector<Thread<ThreadData>> _threads;利用vector容器將所有的線程都管理起來
            // 其中需要特別注意ThreadRun這個成員函數(shù),他是整個線程池中的線程運(yùn)行函數(shù),后續(xù)如何詳見ThreadRun函數(shù)!
            lg.LogMessage(Info, "%s is created...\n", threadname.c_str()); //日志信息,lg在日志類中已定義

        }
    }
    public:
    bool Start() //啟動線程
    {
        for(auto &thread : _threads) //循環(huán)將所有線程啟動
        {
            thread.Start(); //調(diào)用thread類中的啟動線程
            lg.LogMessage(Info, "%s is running ...\n", thread.ThreadName().c_str());
        }
        return true;
    }

    void ThreadWait(const ThreadData &td) //根據(jù)條件變量線程等待的封裝
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond,&_mutex);

    }
    void ThreadWakeup() //喚醒根據(jù)條件變量線程等待的封裝
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadRun(ThreadData &td) //真正的線程運(yùn)行的函數(shù),在前面已經(jīng)被_threads容器管理起來了
    {
        while(true)
        {
            T t; //任務(wù)的創(chuàng)建用于給對應(yīng)的任務(wù)
            { //先給鎖,保證原子性
                LockGuard lockguard(&_mutex);
                while(_q.empty()) //任務(wù)隊列中為空則等待
                {
                    ThreadWait(td);
                    lg.LogMessage(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                }
                t=_q.front(); //拿取任務(wù)
                _q.pop();
            }
            t(); //重載了() 就是運(yùn)行任務(wù)的意思
            lg.LogMessage(Debug, "%s handler task %s done, result is : %s\n",
                          td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }
    void Push(T &in) //給外部將任務(wù)推送進(jìn)隊列的接口
    {
         lg.LogMessage(Debug, "other thread push a task, task is : %s\n", in.PrintTask().c_str());
         LockGuard lockguard(&_mutex);
         _q.push(in);
         ThreadWakeup(); //推送完成了那么久喚醒正在等待的線程
    }
    ~ThreadPool() //析構(gòu)時自動釋放資源
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    void Wait() //外部用于統(tǒng)一回收線程資源
    {
        for(auto &thread :_threads)
        {
            thread.Join();
        }
    }
private:
    std::queue<T> _q; //任務(wù)隊列 
    std::vector<Thread<ThreadData>> _threads; //線程管理容器
    int _thread_num; //線程數(shù)量
    pthread_mutex_t _mutex; //互斥鎖
    pthread_cond_t _cond; //條件變量
};

????????調(diào)用線程池的順序:

????????1、創(chuàng)建線程池。

????????2、啟動線程池。

????????3、將任務(wù)傳入線程池,線程池會自動處理。

????????如下為一個示例:

#include <iostream>
#include <memory>
#include <ctime>
#include "ThreadPool.hpp"
#include "Task.hpp"


int main()
{
    std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>()); //利用智能指針創(chuàng)建線程池
    tp->Start(); //啟動線程池

    srand((uint64_t)time(nullptr) ^ getpid());

    while (true)
    {

        int x = rand() % 100 + 1; /->此處開始到——
        usleep(1234);
        int y = rand() % 200;
        usleep(1234);
        char oper = opers[rand() % opers.size()]; 

        Task t(x, y, oper);
        std::cout << "make task: " << t.PrintTask() << std::endl; /<- 這段只是任務(wù)的前置工作

        tp->Push(t); //推送任務(wù)進(jìn)入線程池的任務(wù)隊列處理
        sleep(1);
    }

    tp->Wait(); //回收線程池資源
    return 0;
}

實現(xiàn)效果:

Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵,Linux練功 初階功法,linux,運(yùn)維,設(shè)計模式,單例模式,服務(wù)器?

使用單例模式改造線程池

單例模式的理解

????????單例模式是一種創(chuàng)建型設(shè)計模式,它確保一個類僅有一個實例,并提供一個全局訪問點(diǎn)來訪問這個唯一實例。在軟件設(shè)計中,單例模式用于限制某個類只能創(chuàng)建一個對象。這個類提供了一種訪問其唯一對象的方法,可以直接訪問而不需要實例化該類。

????????單例模式的主要優(yōu)點(diǎn)是:

  1. 全局唯一實例:由于單例模式限制了類的實例化次數(shù),因此可以確保全局只有一個唯一的實例。這有助于節(jié)省系統(tǒng)資源,避免不必要的重復(fù)創(chuàng)建和銷毀對象。
  2. 簡化訪問:通過提供一個全局訪問點(diǎn),可以方便地獲取到類的唯一實例,無需每次使用時都進(jìn)行實例化。
  3. 安全性:在某些場景下,如數(shù)據(jù)庫連接、文件操作等,需要保證只有一個實例進(jìn)行操作,以避免資源沖突或數(shù)據(jù)不一致的問題。單例模式可以確保這種安全性。

????????然而,單例模式也存在一些潛在的問題和缺點(diǎn):

  1. 擴(kuò)展性問題:由于單例模式限制了類的實例化次數(shù),因此可能不適用于需要多個實例的場景。這可能導(dǎo)致代碼的可擴(kuò)展性受到限制。
  2. 測試?yán)щy:由于單例模式的唯一實例特性,可能導(dǎo)致在單元測試中難以模擬和替換對象,從而增加了測試的復(fù)雜性。
  3. 隱藏依賴:使用單例模式的代碼可能隱式地依賴于全局唯一實例的存在,這可能導(dǎo)致代碼之間的耦合度增加,降低代碼的可維護(hù)性。

????????單例模式的分類主要包括以下三種:

  1. 餓漢式單例:這種單例模式在類被加載的時候,就創(chuàng)建了唯一實例。因此,它天然就是線程安全的。其優(yōu)點(diǎn)在于沒有線程安全的問題,但由于實例在初始化時就已經(jīng)建好,可能會浪費(fèi)一些內(nèi)存空間。
  2. 懶漢式單例:與餓漢式不同,懶漢式單例在類被加載時并不會創(chuàng)建實例,而是在首次調(diào)用getInstance()方法時才進(jìn)行創(chuàng)建。因此,懶漢式單例在延遲加載和節(jié)省內(nèi)存方面有一定的優(yōu)勢。但是,懶漢式單例在實現(xiàn)時需要注意線程安全問題,否則可能會出現(xiàn)多個線程同時創(chuàng)建實例的情況,破壞單例的唯一性。
  3. 登記式單例:這種單例模式是通過將類本身作為一個鍵,將類的唯一實例存儲在某個靜態(tài)的存儲結(jié)構(gòu)中,如Map,以便隨時訪問。這種方式更為靈活,但實現(xiàn)起來相對復(fù)雜一些。

????????在實現(xiàn)單例模式時,需要注意線程安全問題。在多線程環(huán)境下,如果沒有采取適當(dāng)?shù)耐酱胧?,可能會?dǎo)致多個線程同時創(chuàng)建實例,從而破壞單例模式的唯一性。因此,在實現(xiàn)單例模式時,需要確保線程安全,例如通過使用雙重檢查鎖定(double-checked locking)等技術(shù)。(本文會有體現(xiàn))

單例模式的實現(xiàn)

????????本文主要實現(xiàn)的是懶漢式單例,也是根據(jù)上面的線程池進(jìn)行改造而得:

????????我們將構(gòu)造函數(shù)放到了私有但是沒有進(jìn)行改動,改動較大的是我們將拷貝構(gòu)造以及賦值操作給刪除了,這也是為了符合單例模式的特效:全局唯一實例。我們要實現(xiàn)當(dāng)該線程池還沒有被創(chuàng)建出來的時候創(chuàng)建,如果已經(jīng)創(chuàng)建好了那么就返回創(chuàng)建好的指針即可:因此,需要設(shè)置一個最開始就已經(jīng)建立好的指針也就是說要么是全局類型的要么是static的,由于要調(diào)用類內(nèi)的變量,因此我們創(chuàng)建為ThreadPool<T> *ThreadPool<T>::instance;首先設(shè)置為nullptr。接著通過給一個公共的GetInstance()(由于成員變量為static類型,因此函數(shù)也需要為static類型)接口用于外部調(diào)用。在根據(jù)懶漢式的要求首次調(diào)用getInstance()方法時才進(jìn)行創(chuàng)建,否則直接返回指針。需要注意這里有多線程訪問的安全問題,因此需要加上一個鎖(由于函數(shù)為static類型,鎖也需要為static類型)。后續(xù)為了線程的效率問題,如果每次調(diào)用都需要加鎖才能調(diào)用,那么效率會很低,因此加上一句 if (instance == nullptr) 判斷是否已經(jīng)創(chuàng)建該單例來節(jié)省操作,直接返回指針即可。如下為具體的實現(xiàn):

#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

static const int defaultnum = 5; // 默認(rèn)的處理任務(wù)的線程數(shù)量

class ThreadData // 用于傳輸線程的數(shù)據(jù),這里就先傳輸一個線程名
{
public:
    ThreadData(const std::string &name) : threadname(name)
    {
    }

public:
    std::string threadname;
};

template <class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = defaultnum) : _thread_num(thread_num) // 構(gòu)造線程池,可以指定處理任務(wù)的線程數(shù)量
    {
        pthread_mutex_init(&_mutex, nullptr); // 初始化鎖和條件變量
        pthread_cond_init(&_cond, nullptr);

        for (int i = 0; i < _thread_num; i++) // 創(chuàng)建線程,這里我們引用了之前寫的線程接口:Thread(const std::string &threadname, func_t<T> func, T &data)
        {
            std::string threadname = "thread-"; // 構(gòu)建線程名
            threadname += std::to_string(i + 1);
            ThreadData td(threadname); // 線程要傳入的數(shù)據(jù)

            _threads.emplace_back(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td); // std::vector<Thread<ThreadData>> _threads;利用vector容器將所有的線程都管理起來
            // 其中需要特別注意ThreadRun這個成員函數(shù),他是整個線程池中的線程運(yùn)行函數(shù),后續(xù)如何詳見ThreadRun函數(shù)!
            lg.LogMessage(Info, "%s is created...\n", threadname.c_str()); // 日志信息,lg在日志類中已定義
        }
    }

    ThreadPool(const ThreadPool<T> &tp) = delete;

    ThreadPool<T> &operator=(const ThreadPool<T> &cp) = delete;

public:
    static ThreadPool<T> *GetInstance()
    {
        if (instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);
            if (instance == nullptr)
            {
                lg.LogMessage(Info, "創(chuàng)建單例成功...\n");
                instance = new ThreadPool<T>();
            }
        }
        return instance;
    }

    bool Start() // 啟動線程
    {
        for (auto &thread : _threads) // 循環(huán)將所有線程啟動
        {
            thread.Start(); // 調(diào)用thread類中的啟動線程
            lg.LogMessage(Info, "%s is running ...\n", thread.ThreadName().c_str());
        }
        return true;
    }

    void ThreadWait(const ThreadData &td) // 根據(jù)條件變量線程等待的封裝
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }
    void ThreadWakeup() // 喚醒根據(jù)條件變量線程等待的封裝
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadRun(ThreadData &td) // 真正的線程運(yùn)行的函數(shù),在前面已經(jīng)被_threads容器管理起來了
    {
        while (true)
        {
            T t; // 任務(wù)的創(chuàng)建用于給對應(yīng)的任務(wù)
            {    // 先給鎖,保證原子性
                LockGuard lockguard(&_mutex);
                while (_q.empty()) // 任務(wù)隊列中為空則等待
                {
                    ThreadWait(td);
                    lg.LogMessage(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                }
                t = _q.front(); // 拿取任務(wù)
                _q.pop();
            }
            t(); // 重載了() 就是運(yùn)行任務(wù)的意思
            lg.LogMessage(Debug, "%s handler task %s done, result is : %s\n",
                          td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }
    void Push(T &in) // 給外部將任務(wù)推送進(jìn)隊列的接口
    {
        lg.LogMessage(Debug, "other thread push a task, task is : %s\n", in.PrintTask().c_str());
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeup(); // 推送完成了那么久喚醒正在等待的線程
    }
    ~ThreadPool() // 析構(gòu)時自動釋放資源
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    void Wait() // 外部用于統(tǒng)一回收線程資源
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

private:
    std::queue<T> _q;                         // 任務(wù)隊列
    std::vector<Thread<ThreadData>> _threads; // 線程管理容器
    int _thread_num;                          // 線程數(shù)量
    pthread_mutex_t _mutex;                   // 互斥鎖
    pthread_cond_t _cond;                     // 條件變量

    static ThreadPool<T> *instance;
    static pthread_mutex_t sig_lock;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;
// 擴(kuò)展1:

// int _task_num;

// int _thread_num_low_water;  // 3
// int _thread_num_high_water; // 10
// int _task_num_low_water;    // 0
// int _task_num_high_water;   // 30

?


????????????????????? ? ?感謝你耐心的看到這里?( ′???` )比心,如有哪里有錯誤請?zhí)咭荒_作者o(╥﹏╥)o!?

????????????????????????????????? ? ? ?Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵,Linux練功 初階功法,linux,運(yùn)維,設(shè)計模式,單例模式,服務(wù)器

????????????????????????????????????????????????????????????????????????給個三連再走嘛~??文章來源地址http://www.zghlxwxcb.cn/news/detail-850810.html

到了這里,關(guān)于Linux下線程池詳解與實現(xiàn):提升多任務(wù)處理效率的關(guān)鍵的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 智慧園區(qū)預(yù)約管理系統(tǒng):提升效率與保障安全的關(guān)鍵

    智慧園區(qū)預(yù)約管理系統(tǒng):提升效率與保障安全的關(guān)鍵

    在當(dāng)今這個信息技術(shù)高度發(fā)達(dá)的時代,智慧園區(qū)如雨后春筍般迅速發(fā)展,而預(yù)約管理作為智慧園區(qū)的關(guān)鍵組成部分,其重要性日益凸顯。 訪客預(yù)約系統(tǒng)的精細(xì)化設(shè)計,為園區(qū)的安全和秩序提供了堅實可靠的保障。 訪客可以通過便捷的在線平臺,詳細(xì)準(zhǔn)確地填寫個人身份信息

    2024年04月12日
    瀏覽(29)
  • 提升科研效率的關(guān)鍵:掌握3D科研繪圖技能【文末送書】

    提升科研效率的關(guān)鍵:掌握3D科研繪圖技能【文末送書】

    3D科研繪圖在現(xiàn)代科研中扮演著越來越重要的角色。它能夠?qū)?fù)雜的科學(xué)概念和數(shù)據(jù)以直觀、形象的方式展示出來,提高理解度,提升溝通效率,增強(qiáng)決策能力,并擴(kuò)大應(yīng)用領(lǐng)域。這種可視化的方式不僅可以在科學(xué)研究中有用,也在城市規(guī)劃、產(chǎn)品設(shè)計、醫(yī)學(xué)影像等領(lǐng)域發(fā)揮

    2024年02月08日
    瀏覽(21)
  • XXL-Job:提升任務(wù)調(diào)度效率的開源利器

    XXL-Job:提升任務(wù)調(diào)度效率的開源利器

    XXL-Job是由知名技術(shù)公司XXL-Tech團(tuán)隊開發(fā)和維護(hù)的,經(jīng)過多年的發(fā)展和應(yīng)用實踐,已在眾多企業(yè)和項目中獲得廣泛認(rèn)可。它的特性和功能旨在簡化任務(wù)調(diào)度的管理和執(zhí)行,提高開發(fā)效率。 在本文中,我們將探討XXL-Job的關(guān)鍵特點(diǎn),包括其分布式任務(wù)調(diào)度能力、任務(wù)監(jiān)控和管理功

    2024年02月13日
    瀏覽(27)
  • for循環(huán)內(nèi)線程池并發(fā)執(zhí)行任務(wù),等到子線程全部處理完任務(wù),主線程在執(zhí)行java的實現(xiàn)方式

    for循環(huán)內(nèi)線程池并發(fā)執(zhí)行任務(wù),等到子線程全部處理完任務(wù),主線程在執(zhí)行 方式一 使用 CountDownLatch 在 Java 中,您可以使用 CountDownLatch 來實現(xiàn)主線程等待子線程執(zhí)行完成的功能。CountDownLatch 是一個同步工具類,它允許一個或多個線程等待其他線程完成操作后再繼續(xù)執(zhí)行。 具

    2024年02月11日
    瀏覽(21)
  • 提升生產(chǎn)效率的關(guān)鍵:如何選擇適合您企業(yè)的設(shè)備管理系統(tǒng)?

    提升生產(chǎn)效率的關(guān)鍵:如何選擇適合您企業(yè)的設(shè)備管理系統(tǒng)?

    在現(xiàn)代工業(yè)生產(chǎn)中,設(shè)備管理對于提升生產(chǎn)效率和降低成本至關(guān)重要。一個高效的設(shè)備管理系統(tǒng)可以幫助企業(yè)實現(xiàn)設(shè)備的有效監(jiān)控、維護(hù)和優(yōu)化,從而提高設(shè)備的可靠性、降低停機(jī)時間,并最終提升生產(chǎn)效率。選擇適合企業(yè)的設(shè)備管理系統(tǒng)可能是一個復(fù)雜的過程,以下維度可

    2024年02月12日
    瀏覽(92)
  • 提升半導(dǎo)體制造效率,了解半導(dǎo)體CMS系統(tǒng)的關(guān)鍵作用

    提升半導(dǎo)體制造效率,了解半導(dǎo)體CMS系統(tǒng)的關(guān)鍵作用

    隨著半導(dǎo)體制造業(yè)的不斷發(fā)展,提高生產(chǎn)效率成為企業(yè)追求的核心目標(biāo)。在這一背景下,CMS系統(tǒng)(中央設(shè)備狀態(tài)監(jiān)控系統(tǒng))的關(guān)鍵作用愈發(fā)凸顯。本文將深入探討CMS系統(tǒng)在提升半導(dǎo)體制造效率方面的關(guān)鍵作用,幫助讀者全面了解該系統(tǒng)的重要性和潛在價值。 圖.半導(dǎo)體芯片制

    2024年02月11日
    瀏覽(29)
  • GPT-4助力數(shù)據(jù)分析:提升效率與洞察力的未來關(guān)鍵技術(shù)

    隨著大數(shù)據(jù)時代的到來,數(shù)據(jù)分析已經(jīng)成為企業(yè)和組織的核心競爭力。然而,傳統(tǒng)的數(shù)據(jù)分析方法往往無法滿足日益增長的數(shù)據(jù)分析需求的數(shù)量和復(fù)雜性。在這種背景下,ChatGPT-4作為一種先進(jìn)的自然語言處理技術(shù),為數(shù)據(jù)分析帶來了革命性的提升,助力企業(yè)和組織更高效地挖

    2024年02月13日
    瀏覽(31)
  • 電商(淘寶1688京東拼多多等)API接口服務(wù):提升商業(yè)效率和用戶體驗的關(guān)鍵

    電商(淘寶1688京東拼多多等)API接口服務(wù):提升商業(yè)效率和用戶體驗的關(guān)鍵

    電商API接口服務(wù):提升商業(yè)效率和用戶體驗的關(guān)鍵 隨著電子商務(wù)的飛速發(fā)展,電商企業(yè)需要不斷提升自身的業(yè)務(wù)能力和服務(wù)質(zhì)量,以應(yīng)對日益激烈的市場競爭。為了更好地滿足商家和消費(fèi)者的需求,電商API接口服務(wù)應(yīng)運(yùn)而生。本文將探討電商API接口服務(wù)的作用和價值,以及如

    2024年02月09日
    瀏覽(27)
  • GPT-4助力數(shù)據(jù)分析:提升效率與洞察力的未來關(guān)鍵技術(shù) | 京東云技術(shù)團(tuán)隊

    GPT-4助力數(shù)據(jù)分析:提升效率與洞察力的未來關(guān)鍵技術(shù) | 京東云技術(shù)團(tuán)隊

    隨著大數(shù)據(jù)時代的到來,數(shù)據(jù)分析已經(jīng)成為企業(yè)和組織的核心競爭力。然而,傳統(tǒng)的數(shù)據(jù)分析方法往往無法滿足日益增長的數(shù)據(jù)分析需求的數(shù)量和復(fù)雜性。在這種背景下,ChatGPT-4作為一種先進(jìn)的自然語言處理技術(shù),為數(shù)據(jù)分析帶來了革命性的提升,助力企業(yè)和組織更高效地挖

    2024年02月13日
    瀏覽(20)
  • Linux基于多線程和任務(wù)隊列實現(xiàn)生產(chǎn)消費(fèi)模型

    Linux基于多線程和任務(wù)隊列實現(xiàn)生產(chǎn)消費(fèi)模型

    目錄 一、生產(chǎn)者消費(fèi)者模型 二、代碼實現(xiàn)模型 2.1 BlockQueue.hpp 2.2 MainCP.cc 2.3 執(zhí)行結(jié)果 三、效率優(yōu)勢 將上述圖片邏輯轉(zhuǎn)換成代碼邏輯就是,一批線程充當(dāng)生產(chǎn)者角色,一批線程充當(dāng)消費(fèi)者角色,倉庫是生產(chǎn)者和消費(fèi)者獲取的公共資源!下面我想用 321原則 來解釋這個模型。 既

    2024年02月09日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包