Linux--線程池(包含日志的解釋)

線程系列:
Linux–線程的認識(一)
Linux–線程的分離、線程庫的地址關系的理解、線程的簡單封裝(二)
線程的互斥:臨界資源只能在同一時間被一個線程使用
生產消費模型
信號量

線程池

線程池(Thread Pool)是一種基于池化技術設計用于管理復用線程的機制
在多線程編程中,頻繁地創建和銷毀線程會消耗大量的系統資源,并且由于線程的創建和銷毀需要時間,這也會降低程序的執行效率。線程池通過預先創建一定數量的線程并放入池中,需要時從池中取出線程執行任務,執行完畢后線程并不銷毀而是重新放回池中等待下一次使用,從而避免了線程的頻繁創建和銷毀所帶來的開銷。

主要優點

  • 降低資源消耗:通過復用已存在的線程,減少線程創建和銷毀的開銷。
  • 提高響應速度:當任務到達時,可以立即分配線程進行處理,減少了等待時間。
  • 提高線程的可管理性:線程池可以統一管理線程,包括線程的創建、調度、執行和銷毀等。

關鍵參數

  • 核心線程數:線程池維護線程的最少數量,即使這些線程處于空閑狀態,線程池也不會回收它們(一般為主線程)。
  • 最大線程數:線程池中允許的最大線程數。
  • 阻塞隊列:用于存放待執行的任務的隊列。當線程池中的所有線程都忙時,新任務會被添加到這個隊列中等待處理。
  • 非核心線程空閑存活時間:當線程池中的線程數量超過核心線程數時,如果線程空閑時間超過這個時間,多余的線程將被終止。
  • 線程工廠:用于創建新線程的工廠。
  • 拒絕策略:當線程池和隊列都滿了時,對于新來的任務將采取的拒絕策略。

實現原理

線程池的實現原理通常包括以下幾個關鍵部分:

  • 線程池管理器:負責創建并管理線程池,包括初始化線程池、創建工作線程、銷毀線程池等。
  • 工作線程:線程池中的線程,負責執行具體的任務。工作線程通常會不斷從任務隊列中取出任務并執行,直- 到線程池被銷毀或所有任務都執行完畢。
  • 任務接口:每個任務必須實現的接口,用于定義任務的執行邏輯。在Java中,這通常是通過實現Runnable或Callable接口來實現的。
  • 任務隊列:用于存放待處理的任務。當線程池中的工作線程數量達到最大值時,新到達的任務會被放入任務隊列中等待處理。任務隊列的實現通常依賴于Java的BlockingQueue接口。

實現流程

  • 當有新任務提交給線程池時,線程池會首先判斷當前正在運行的線程數量是否小于核心線程數。如果是,則直接創建新的線程來執行任務;否則,將任務加入任務隊列等待處理。
  • 如果任務隊列已滿,且當前正在運行的線程數量小于最大線程數(maximumPoolSize),則創建新的線程來處理任務;如果線程數量已經達到最大線程數,則根據配置的拒絕策略來處理新任務(如拋出異常、直接丟棄等)。
  • 當一個線程完成任務后,它會從任務隊列中取下一個任務來執行;如果沒有任務可供執行,并且線程池中的線程數量超過了核心線程數,且這些線程空閑時間超過了設定的存活時間,則這些線程會被銷毀,直到線程池中的線程數量減少到核心線程數為止。

實例

Thread.hpp

#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include<iostream>
#include<string>
#include<pthread.h>
#include<functional>
#include<unistd.h>using namespace std;namespace ThreadMdule
{using func_t = std::function<void(string)>;class Thread{public:void Excute(){_func(_threadname);}Thread(func_t func, const std::string &name="none-name"): _func(func), _threadname(name), _stop(true){}static void* threadroutine(void* args){Thread* self=static_cast<Thread*>(args);self->Excute();return nullptr;}bool start(){int n=pthread_create(&_tid,nullptr,threadroutine,this);if(!n){_stop = false;return true;}else{return false;}}void Detach(){if(!_stop){pthread_detach(_tid);}}void Join(){if(!_stop){pthread_join(_tid,nullptr);}}string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;std::string _threadname;func_t _func;bool _stop;};
}#endif

ThreadPool.hpp

#pragma once#include<iostream>
#include<vector>
#include<queue>
#include<pthread.h>
#include"Thread.hpp"
#include"Log.hpp"
#include"LockGuard.hpp"
using namespace ThreadMdule;
using namespace std;
const static int gdefaultthreadnum=3;//默認線程池的線程數template <class T>
class ThreadPool
{
public:ThreadPool(int threadnum=gdefaultthreadnum) :_threadnum(threadnum),_waitnum(0),_isrunning(false){pthread_mutex_init(&_mutex,nullptr);pthread_cond_init(&_cond,nullptr);LOG(INFO,"ThreadPool COnstruct.");}//各個線程獨立的任務函數void HandlerTask(string name){LOG(INFO,"%s is running...",name.c_str());while(true){LockQueue();//開啟保護//等到有任務時才退出循環執行下列語句while(_task_queue.empty()&&_isrunning){_waitnum++;ThreadSleep();_waitnum--;}//當任務隊列空并且線程池停止時線程退出if(_task_queue.empty()&&!_isrunning){UnlockQueue();cout<<name<<" quit "<<endl;sleep(1);break;}//1.任務隊列不為空&&線程池開啟//2.任務隊列不為空&&線程池關閉,直到任務隊列為空//所以,只要有任務,就要處理任務T t=_task_queue.front();//取出對應任務_task_queue.pop();UnlockQueue();LOG(DEBUG,"%s get a task",name.c_str());//處理任務t();LOG(DEBUG,"%s handler a task,result is: %s",name.c_str(),t.ResultToString().c_str());}}//線程池中線程的構建void InitThreadPool(){for(int i=0;i<_threadnum;i++){string name="thread-"+to_string(i+1);_threads.emplace_back(bind(&ThreadPool::HandlerTask,this,placeholders::_1),name);LOG(INFO,"init thread %s done",name.c_str());}_isrunning=true;}//線程池的啟動void Start(){for(auto& thread:_threads){thread.start();}}//線程池停止void Stop(){LockQueue();_isrunning=false;ThreadWakeupAll();UnlockQueue();}void Wait(){for(auto& thread:_threads){thread.Join();LOG(INFO,"%s is quit...",thread.name().c_str());}}//將任務入隊列bool Enqueue(const T& t){bool ret=false;LockQueue();if(_isrunning){_task_queue.push(t);//如果有空閑的線程,那么喚醒線程讓其執行任務if(_waitnum>0){ThreadWakeup();}LOG(DEBUG,"enqueue task success");ret=true;}UnlockQueue();return ret;}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}int _threadnum;//線程數vector<Thread> _threads;//存儲線程的vectorqueue<T> _task_queue;//輸入的任務隊列pthread_mutex_t _mutex;//互斥鎖pthread_cond_t _cond;//條件變量int _waitnum;//空閑的線程數bool _isrunning;//表示線程池是否啟動};

Task.hpp

#include<iostream>
#include<string>
#include<functional>
using namespace std;class Task
{
public:Task(){}Task(int a,int b): _a(a),_b(b),_result(0){}void Excute(){_result=_a+_b;}string ResultToString(){return to_string(_a) + "+"+to_string(_b)+"="+to_string(_result);}string DebugToString(){return to_string(_a) + "+" + to_string(_b) + "= ?";}void operator()(){Excute();}
private:int _a;int _b;int _result;
};

main.cc

int main()
{srand(time(nullptr)^getpid()^pthread_self());//EnableScreen();EnableFile();unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>(5));tp->InitThreadPool();tp->Start();int tasknum=10;while(tasknum){sleep(1);int a=rand()%10+1;usleep(1024);int b=rand()%20+1;Task t(a,b);LOG(INFO,"main thread push task: %s",t.DebugToString().c_str());tp->Enqueue(t);tasknum--;}tp->Stop();tp->Wait();
}

Loh.hpp

#pragma once#include<iostream>
#include<fstream>
#include<ctime>
#include<cstdarg>
#include<string>
#include<sys/types.h>
#include<unistd.h>
#include<cstdio>
#include"LockGuard.hpp"using namespace std;bool gIsSave=false;//默認輸出到屏幕
const string logname="log.txt";
//1.日志是有等級的
enum Level
{DEBUG=0,INFO,WARNING,ERROR,FATAL 
};void SaveFile(const string& filename,const string& messages)
{ofstream out(filename,ios::app);if(!out.is_open()){return;}out<<messages;out.close();
}
//等級轉化為字符串
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 "Unkonwn";}
}//獲取當前時間
string GetTimeString()
{time_t curr_time=time(nullptr);//時間戳struct tm* format_time=localtime(&curr_time);//轉化為時間結構if(format_time==nullptr)return "None";char time_buffer[1024];snprintf(time_buffer,sizeof(time_buffer),"%d-%d-%d %d:%d:%d",format_time->tm_year + 1900,format_time->tm_mon + 1,format_time->tm_mday,format_time->tm_hour,format_time->tm_min,format_time->tm_sec);return time_buffer;}pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
//獲取日志信息
void LogMessage(string filename,int line,bool issave,int level,char* format,...)
{string levelstr=LevelToString(level);string timestr=GetTimeString();pid_t selfid=getpid();char buffer[1024];va_list arg;va_start(arg,format);vsnprintf(buffer,sizeof(buffer),format,arg);va_end(arg);string message= "[" + timestr + "]" + "[" + levelstr + "]" +"[" + std::to_string(selfid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";LockGuard lockguard(&lock);if(!issave){cout<<message;}else{SaveFile(logname,message);}}#define LOG(level,format,...)                                               \do                                                                        \{                                                                          \LogMessage(__FILE__,__LINE__,gIsSave,level,format,##__VA_ARGS__);       \} while (0)#define EnableFile()         \do                       \{                        \gIsSave=true;        \  } while (0)#define EnableScreen()         \do                         \{                          \gIsSave=false;         \  } while (0)

線程池解釋(代碼)

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

日志解釋(代碼)

日志是系統或程序記錄所有發生事件的文件:
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/45373.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/45373.shtml
英文地址,請注明出處:http://en.pswp.cn/web/45373.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Qt 統計圖編程

學習目標&#xff1a;Qt 折線圖&#xff0c;柱形圖和扇形統計圖編程 學習基礎 Qt QChart 曲線圖表操作-CSDN博客 學習內容 Qt中繪制三種常見的圖表非常方便, 主要步驟如下: 1. 折線圖: - 使用QLineSeries定義折線數據,添加多個坐標點 - 使用QValueAxis創建X軸和Y軸 - 將…

dockerfile配置和yml配置

dockerfile docker build 使用dockerfile自動構建鏡像文件 FROM python:3.9WORKDIR /appCOPY requirements.txt. RUN pip install -r requirements.txtCOPY..CMD ["python", "main.py"]docker build dockerifle自動構建拉取python3.9鏡像&#xff0c;并執…

拷貝文件的一些操作

利用fputc 、fgetc實現文件的拷貝 int main(int argc, const char *argv[]) {FILE* rfpfopen(argv[1],"r");FILE* wfpfopen(argv[2],"w");if(rfpNULL || wfpNULL){perror("fopen");return 1;}while(1){char resfgetc(rfp);if(feof(rfp)1){break;…

PointCloudLib LocalMaximum_DeleteMaxPoint C++版本

測試效果 簡介 在點云庫&#xff08;Point Cloud Library&#xff0c;PCL&#xff09;中&#xff0c;處理點云數據時&#xff0c;經常需要去除局部最大點&#xff08;Local Maximum&#xff09;&#xff0c;這通常用于去除噪聲、提取特定形狀的特征或者簡化點云數據。局部最大…

[米聯客-安路飛龍DR1-FPSOC] FPGA基礎篇連載-14 SPI MASET發送程序設計

軟件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系統&#xff1a;WIN10 64bit 硬件平臺&#xff1a;適用安路(Anlogic)FPGA 實驗平臺&#xff1a;米聯客-MLK-L1-CZ06-DR1M90G開發板 板卡獲取平臺&#xff1a;https://milianke.tmall.com/ 登錄“米聯客”FPGA社區 ht…

數據庫管理-第220期 Oracle的高可用-03(20240715)

數據庫管理220期 2024-07-15 數據庫管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09;1 AC/TAC2 配置Service3 用戶權限4 端口開放總結 數據庫管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09; 作者&#xff1a;胖頭魚的魚缸&#xff08;尹海文…

Modbus - 筆記

1 Modbus Poll/Slave 模擬器使用教程 Modbus Poll/Slave 模擬器使用教程_modbus poll 使用教程-CSDN博客 https://item.jd.com/67488830087.html

Node.js 爬蟲開發實戰:構建一個高效、優雅的網絡數據抓取器

在大數據時代&#xff0c;從網頁上自動抓取數據的需求日益增長。Node.js&#xff0c;以其異步非阻塞I/O模型&#xff0c;成為了構建高性能網絡爬蟲的理想選擇。本文將引導你如何使用Node.js&#xff0c;結合axios和cheerio兩個流行庫&#xff0c;創建一個能夠從目標網站抓取信息…

51單片機10(蜂鳴器介紹)

一、蜂鳴器介紹&#xff1a; 1、蜂鳴器是一種一體化結構的電子訊響器&#xff0c;采用直流電壓供電&#xff0c;廣泛應用于電子產品中作為發聲器件。蜂鳴器主要分為壓電式蜂鳴器和電磁式蜂鳴器。 &#xff08;1&#xff09;壓電式蜂鳴器&#xff0c;它主要由多諧的一個增脹器…

【學習筆記】無人機(UAV)在3GPP系統中的增強支持(八)-通過無人機進行無線接入

引言 本文是3GPP TR 22.829 V17.1.0技術報告&#xff0c;專注于無人機&#xff08;UAV&#xff09;在3GPP系統中的增強支持。文章提出了多個無人機應用場景&#xff0c;分析了相應的能力要求&#xff0c;并建議了新的服務級別要求和關鍵性能指標&#xff08;KPIs&#xff09;。…

電腦出現錯誤——找不到msvcp140.dll無法繼續執行代碼,有效解決錯誤dll文件

msvcp140.dll是一個屬于 Microsoft Visual C Redistributable for Visual Studio 2015 的 DLL 文件。這個文件是許多Windows應用程序&#xff08;尤其是使用 C 開發的程序&#xff09;所必需的&#xff0c;因為它包含了標準 C 庫的函數實現&#xff0c;用于處理數學運算、數據轉…

【React Hooks原理 - useRef】

概述 在Function Component項目中當我們需要操作dom的時候&#xff0c;第一時間想到的就是使用useRef這個Hook來綁定dom。但是這個僅僅是使用這個Hook而已&#xff0c;為了更好的學習React Hooks內部實現原理&#xff0c;知其所以然。所以本文根據源碼從useRef的基礎使用場景一…

使用shell腳本打印99乘法表

一、簡介 前一段時間在舊電腦上安裝 antiX 23.1 操作系統&#xff0c;遇到一些問題需要使用shell腳本解決問題&#xff0c;所以專門學習了幾天&#xff0c;打印99乘法表是其中的一個練習作業。 二、學習Linux可行的幾種方式 虛擬機安裝Linux進行學習直接雙系統安裝在實體電腦…

Ubuntu新系統的使用

1.安裝顯卡驅動 直接到軟件與更新里面&#xff0c;就是一個A字圖標的那個軟件打開&#xff0c;到附加驅動里選擇。要選擇“server driver”的&#xff0c;選擇后確認即可。 然后輸入&#xff1a;nvidia-sim查看 別的方法太復雜&#xff0c;這個方法我親測了兩臺電腦&#xff…

kubebuilder入門

1. 安裝kubebuilder brew install kubebuilder 2. 需求描述 開發一個zk operator。 cr定義為ZooKeeperCluster 3. 開發過程 3.1 創建一個空的文件夾zk-operator mkdir zk-operator 3.2 進入該文件夾 cd zk-operator 3.3 執行初始化 kubebuilder init --domain my.doma…

MWA(Modern Web App)初學那些事-2-Basic HTML CSS

初學MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS 目錄 初學MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS前言一、本節學習目標二、HTML基礎內容2.1關鍵元素2.4 Scripts 三、CSS 基礎內容3.1 級聯樣式表-用于設置網頁樣式和布局3.2 CSS規則語…

springcloud使用微服務的搭建

微服務的搭建 1.配置對應信息 Springboot 、springcloud、springcloud alibaba對應關系 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 2.pom.xml的配置 2.1 總項目pom.xml引入依賴 <parent><groupId>org.sprin…

阿里通義音頻生成大模型 FunAudioLLM 開源

簡介 近年來&#xff0c;人工智能&#xff08;AI&#xff09;技術的進步極大地改變了人類與機器的互動方式&#xff0c;特別是在語音處理領域。阿里巴巴通義實驗室最近開源了一個名為FunAudioLLM的語音大模型項目&#xff0c;旨在促進人類與大型語言模型&#xff08;LLMs&…

vue3在 setup 中訪問路由和當前路由

報錯信息&#xff1a; Cannot read properties of undefined (reading $router) 原因&#xff1a; 因為我們在 setup 里面沒有訪問 this&#xff0c;所以我們不能直接訪問 this.$router 或 this.$route。 解決方案&#xff1a; 作為替代&#xff0c;我們使用 useRouter 和…

Oracle字符集修改

提示 Oracle數據庫默認的字符集編碼為US7ASCII&#xff0c;這個編碼是不支持中文的&#xff0c;如果想要在數據庫存儲中文&#xff0c;就需要修改編碼為ZHS16GBK或UTF-8 編碼和字符集是一個意思&#xff0c;只是叫法不一樣而已 前置條件 修改字符集的前提是知道我們現在用的是什…