欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ 實(shí)現(xiàn)對象池的具體方法

 更新時(shí)間:2022年01月17日 11:52:56   作者:Alfred-N  
本文主要介紹了C++ 實(shí)現(xiàn)對象池的具體方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

需求無限,但資源有限的情況下,就需要對資源進(jìn)行專門的管理。不斷的申請和釋放內(nèi)存是不合理的,會造成內(nèi)存的波動,以及內(nèi)存不受限的增長。比如,實(shí)現(xiàn)了一個(gè)消息隊(duì)列,當(dāng)發(fā)消息的速度快于處理消息的速度時(shí),如果不對資源進(jìn)行控制,就會導(dǎo)致內(nèi)存不斷的增長。除非有專門的內(nèi)存管理機(jī)制,或明確的編譯器優(yōu)化內(nèi)存復(fù)用,否則建立一個(gè)資源管理模塊是很有必要的。對象池就是一個(gè)對限定數(shù)量資源復(fù)用管理的模塊。

一、什么是對象池

復(fù)用對象,消除頻繁的對象創(chuàng)建銷毀帶來的性能消耗,以及避免內(nèi)存增長的不可控。比如,線程池、連接池都是為了實(shí)現(xiàn)復(fù)用對象。
舉個(gè)例子:假設(shè)在生產(chǎn)者消費(fèi)者模型中,生產(chǎn)者生產(chǎn)時(shí)創(chuàng)建對象,消費(fèi)者消費(fèi)后銷毀對象。直接簡單的使用new和delete,就會讓對象頻繁創(chuàng)建和銷毀導(dǎo)致額外性能消耗,而且生產(chǎn)者速度大于消費(fèi)者速度時(shí),就會讓對象數(shù)量創(chuàng)建大于銷毀導(dǎo)致內(nèi)存不受控制增長。如果使用對象池,就可以讓生產(chǎn)和消費(fèi)復(fù)用固定數(shù)量的對象,很好的避免了頻繁創(chuàng)建銷毀對象以及內(nèi)存增長不受控制的情況。

二、如何實(shí)現(xiàn)

1.確定接口

(1)、確定動態(tài)關(guān)系
通過序列圖可以確定對象需要的接口,我們以socket服務(wù)為場景繪制序列圖,如下

在這里插入圖片描述

(2)、確定靜態(tài)關(guān)系
根據(jù)上面的序列圖確定的接口繪制成類圖,如下:

在這里插入圖片描述

2.轉(zhuǎn)成代碼

由于模塊規(guī)模小,接口也不多,所以就不展示進(jìn)一步細(xì)化設(shè)計(jì)了。因?yàn)楸疚闹v述的是C++實(shí)現(xiàn)對象池,所以將上述設(shè)計(jì)轉(zhuǎn)化為C++接口定義。如下:

    /// <summary>
	/// 對象池
	/// </summary>
	class ObjectPool
	{
	public:		
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="bufferArray">對象池的緩沖區(qū),由外部指定,可以理解為一個(gè)數(shù)組。數(shù)組大小需滿足bufferSize>=elementSize*arraySize</param>
		/// <param name="elementSize">數(shù)組元素大小</param>
		/// <param name="arraySize">數(shù)組長度或元素個(gè)數(shù)</param>
		ObjectPool(void* bufferArray, int elementSize, int arraySize );		
		/// <summary>
		/// 申請對象
		/// 如果池里對象不足,則會等待,直到有對象才返回。
		/// </summary>
		/// <returns>返回申請的對象指針</returns>
		void* Applicate();
		/// <summary>
		/// 申請對象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請的對象指針</returns>
		void* Applicate(int timeout);	
		/// <summary>
		/// 歸還對象
		/// </summary>
		/// <param name="element">需歸還的對象</param>
		void ReturnBack(void* element);	
	};

三、完整代碼

根據(jù)上述的初步設(shè)計(jì),再進(jìn)行細(xì)化,以及實(shí)現(xiàn),最終得出如下代碼實(shí)現(xiàn)。
ObjectPool.h

#ifndef OBJECTPOOL_H
#define OBJECTPOOL_H
/************************************************************************
* @Project:  	AC::ObjectPool
* @Decription:  對象池:“需求很大,但數(shù)量有限”的情況下,就需要對資源進(jìn)行專門的管理,
*不斷的申請和釋放對象是不合理的(除非有專門的內(nèi)存管理機(jī)制,或明確的編譯優(yōu)化內(nèi)存復(fù)用)。
*這是一個(gè)對限定數(shù)量資源的復(fù)用管理模塊。
* @Verision:  	v1.0.0.1
* @Author:  	Xin Nie
* @Create:  	2018/12/21 13:34:00
* @LastUpdate:  2022/1/5 13:53:00
************************************************************************
* Copyright @ 2022. All rights reserved.
************************************************************************/
#include<unordered_map>
#include<vector>
#include<mutex>
#include<condition_variable>
namespace AC {
	/// <summary>
	/// 對象池
	/// </summary>
	class ObjectPool
	{
	public:		
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="bufferArray">對象池的緩沖區(qū),由外部指定,可以理解為一個(gè)數(shù)組。數(shù)組大小需滿足bufferSize>=elementSize*arraySize</param>
		/// <param name="elementSize">數(shù)組元素大小</param>
		/// <param name="arraySize">數(shù)組長度或元素個(gè)數(shù)</param>
		ObjectPool(void* bufferArray, int elementSize, int arraySize );
		/// <summary>
		/// 析構(gòu)方法
		/// </summary>
		~ObjectPool();
		/// <summary>
		/// 申請對象
		/// 如果池里對象不足,則會等待,直到有對象才返回。
		/// </summary>
		/// <returns>返回申請的對象指針</returns>
		void* Applicate();
		/// <summary>
		/// 申請對象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請的對象指針</returns>
		void* Applicate(int timeout);	
		/// <summary>
		/// 歸還對象
		/// </summary>
		/// <param name="element">需歸還的對象</param>
		void ReturnBack(void* element);	
		/// <summary>
		/// 獲取對象池的緩沖區(qū),即構(gòu)造方法中的bufferArray
		/// </summary>
		/// <returns>緩沖區(qū)的指針</returns>
		void* GetPoolBuffer();
		/// <summary>
		/// 獲取對象的大小,即構(gòu)造方法中的elementSize
		/// </summary>
		/// <returns>對象的大小</returns>
		int GetObjectSize();
		/// <summary>
		/// 獲取總的對象數(shù)量,即構(gòu)造方法中的arraySize
		/// </summary>
		/// <returns>總的對象數(shù)量</returns>
		int GetObjectCount();
	private:
		void*_buffer = NULL;
		int _elementSize;
		int _arraySize;
		std::vector<void*> _unusedUnits;
		std::unordered_map<void*, int> _usedUnits;
		std::mutex _mutex;
		std::condition_variable _cond;
	};

	/// <summary>
	/// 泛型對象池
	/// </summary>
	/// <typeparam name="T">對象類型</typeparam>
	template<typename T>
	class ObjectPoolGeneric:private ObjectPool
	{
	public:
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="array">對象數(shù)組</param>
		/// <param name="size">數(shù)組大小</param>
		/// <returns></returns>
		ObjectPoolGeneric(T*array,int size) :ObjectPool(array, sizeof(T), size)
		{
		}
		/// <summary>
		/// 析構(gòu)方法
		/// </summary>
		~ObjectPoolGeneric() {}
		/// <summary>
		/// 申請對象
		/// 如果池里對象不足,則會等待,直到有對象才返回。
		/// </summary>
		/// <returns>返回申請的對象指針</returns>
		T* Applicate() {
			return (T*)ObjectPool::Applicate();
		}
		/// <summary>
		/// 申請對象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請的對象指針</returns>
		T* Applicate(int timeout) {
			return (T*)ObjectPool::Applicate(timeout);
		}
		/// <summary>
		/// 歸還對象
		/// </summary>
		/// <param name="element">需歸還的對象</param>
		void ReturnBack(T* element)
		{
			ObjectPool::ReturnBack(element);
		}
		/// <summary>
		/// 獲取對象池的緩沖區(qū),即構(gòu)造方法中的bufferArray
		/// </summary>
		/// <returns>緩沖區(qū)的指針</returns>
		T* GetPoolBuffer() {
			return (T*)ObjectPool::GetPoolBuffer();
		}
	};
}
#endif 

ObjectPool.cpp

#include "ObjectPool.h"
#include <chrono> 
namespace AC {
	ObjectPool::ObjectPool(void* bufferArray, int elementSize, int arraySize)
	{
		if (elementSize < 1 || arraySize < 1)
			return;
		_buffer = bufferArray;
		_elementSize = elementSize;
		_arraySize = arraySize;
		char* firstAdress = (char*)bufferArray;
		//記錄未使用的索引
		for (int i = 0; i < arraySize; i++)
		{
			_unusedUnits.push_back(&(firstAdress[i * elementSize]));
		}
	}
	ObjectPool::~ObjectPool()
	{
	}
	void* ObjectPool::Applicate()
	{
		return Applicate(-1);
	}
	void* ObjectPool::Applicate(int timeout) {
		void* resource = NULL;
		std::unique_lock<std::mutex> l(_mutex);
		while (_unusedUnits.size() < 1)
		{
			if (timeout == -1)
			{
				_cond.wait(l);
			}
			else if (_cond.wait_for(l, std::chrono::microseconds(timeout)) == std::cv_status::timeout)
			{
				return nullptr;
			}
		}
		resource = _unusedUnits.back();
		_usedUnits[resource] = 1;
		_unusedUnits.pop_back();
		return resource;
	}
	void ObjectPool::ReturnBack(void* element) {
		_mutex.lock();
		auto iter = _usedUnits.find(element);
		if (iter != _usedUnits.end())
		{
			_unusedUnits.push_back(element);
			_usedUnits.erase(iter);
			_cond.notify_one();
		}
		_mutex.unlock();
	}
	void* ObjectPool::GetPoolBuffer()
	{
		return _buffer;
	}
	int ObjectPool::GetObjectSize()
	{
		return _elementSize;
	}
	int ObjectPool::GetObjectCount()
	{
		return _arraySize;
	}
}

四、使用示例

1、對象復(fù)用,示例:

#include "ObjectPool.h"
class A {
public:
	A() {
		printf("%p\n", this);
	}
};
int main(int argc, char** argv) {
	//初始化對象池,2個(gè)對象
	AC::ObjectPool objectPool(new char[sizeof(A) * 2], sizeof(A), 2);
	A* a, * b, * c;
	//申請對象,使用定位new初始化對象
	a = new (objectPool.Applicate())A;
	b = new (objectPool.Applicate())A;
	//歸還對象
	a->~A();//返初始化對象
	objectPool.ReturnBack(a);
	c = new (objectPool.Applicate())A;
	b->~A();
	c->~A();
	//使用結(jié)束,刪除緩存
	delete	objectPool.GetPoolBuffer();
	return 0;
}

輸出:
016502E9
016502E8
016502E9

2、簡易的線程池,示例:

#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include "ObjectPool.h"
class ThreadInfo {
public:
	std::thread* pThread;
	std::mutex _mutext;
	std::condition_variable _cv;
	std::function<void()> _threadPoc;
};
//線程信息數(shù)組,數(shù)組長度即線程池的線程數(shù)
ThreadInfo _threadArray[3];
//對象池,使用線程信息數(shù)組初始化
AC::ObjectPoolGeneric<ThreadInfo>_threadPool(_threadArray, 3);
bool _exitThreadPool = false;
//在線程池中運(yùn)行方法
void RunInThreadPool(std::function<void()> f) {
	//申請線程
	auto threadInfo = _threadPool.Applicate();
	threadInfo->_threadPoc = f; 
	if (threadInfo->pThread)
		//復(fù)用線程
	{
		threadInfo->_cv.notify_one();
	}
	else
		//創(chuàng)建線程
	{
		threadInfo->pThread = new std::thread([=]() {
			while (!_exitThreadPool)
			{
				printf("thread %d run\n", threadInfo->pThread->get_id());
				if (threadInfo->_threadPoc)
				{	//執(zhí)行線程操作
					threadInfo->_threadPoc();
				}
				printf("thread %d stop\n", threadInfo->pThread->get_id());
				//歸還線程
				_threadPool.ReturnBack(threadInfo);
				std::unique_lock<std::mutex>lck(threadInfo->_mutext);
				threadInfo->_cv.wait(lck);
			}
		});
	}
}
int main(int argc, char** argv) {
	while(true)
	{   //在線程池中運(yùn)行方法
		RunInThreadPool([]() {		
			std::this_thread::sleep_for(std::chrono::milliseconds(1000));	
		});
	}
    return 0;
}

輸出:
thread 69664 run
thread 57540 run
thread 56876 run
thread 69664 stop
thread 69664 run
thread 57540 stop
thread 56876 stop
thread 57540 run
thread 56876 run
thread 69664 stop
thread 69664 run
thread 56876 stop
thread 57540 stop
thread 56876 run
thread 57540 run
thread 69664 stop

總結(jié)

以上就是今天要講的內(nèi)容,本文介紹了對象池的設(shè)計(jì)與實(shí)現(xiàn)以及使用,其使用場景其實(shí)不算多,因?yàn)楹芏嘈枰獙ο髲?fù)用的場景通常以及有底層實(shí)現(xiàn)了,比如線程池?cái)?shù)據(jù)庫的連接池等,所以本文講的內(nèi)容只能適用于少數(shù)的場景,比如waveOut播放音頻時(shí)是可以使用對象池實(shí)現(xiàn) 的。但總得來說,對象池還是有用的,所以將其寫成博客用于記錄曾經(jīng)用過的技術(shù)。

到此這篇關(guān)于C++ 實(shí)現(xiàn)對象池的具體方法的文章就介紹到這了,更多相關(guān)C++ 對象池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++淺析程序中內(nèi)存的分布

    C++淺析程序中內(nèi)存的分布

    這篇文章主要介紹了C++內(nèi)存分布及用法,從內(nèi)存的基礎(chǔ)概念到內(nèi)存分配進(jìn)行了講解,內(nèi)存是我們開發(fā)中最重要的一部分,往往邏輯上的錯(cuò)誤就會造成內(nèi)存泄漏,導(dǎo)致程序無法運(yùn)行,下面我們就來了解文章對該內(nèi)容的詳細(xì)介紹
    2022-08-08
  • OpenCV圖像旋轉(zhuǎn)Rotate的詳細(xì)介紹

    OpenCV圖像旋轉(zhuǎn)Rotate的詳細(xì)介紹

    這篇文章主要介紹了OpenCV圖像旋轉(zhuǎn)Rotate,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C++實(shí)現(xiàn)簡易版掃雷游戲

    C++實(shí)現(xiàn)簡易版掃雷游戲

    大家好,本篇文章主要講的是C++實(shí)現(xiàn)簡易版掃雷游戲,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • 學(xué)習(xí)C語言要掌握的幾個(gè)庫

    學(xué)習(xí)C語言要掌握的幾個(gè)庫

    本文給大家分享的是網(wǎng)友提出的學(xué)習(xí)C語言要掌握的幾個(gè)庫,這里分享給大家,有需要的小伙伴可以參考下。
    2015-07-07
  • c++動態(tài)庫調(diào)用的實(shí)現(xiàn)

    c++動態(tài)庫調(diào)用的實(shí)現(xiàn)

    本文主要介紹了c++動態(tài)庫調(diào)用的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Qt?自定義屬性Q_PROPERTY不顯示float類型的解決

    Qt?自定義屬性Q_PROPERTY不顯示float類型的解決

    這篇文章主要介紹了Qt?自定義屬性Q_PROPERTY不顯示float類型的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言實(shí)現(xiàn)動態(tài)版通訊錄的代碼分享

    C語言實(shí)現(xiàn)動態(tài)版通訊錄的代碼分享

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)一個(gè)簡單的動態(tài)版通訊錄,主要運(yùn)用了結(jié)構(gòu)體,一維數(shù)組,函數(shù),分支與循環(huán)語句等等知識,需要的可以參考一下
    2023-01-01
  • C++ 實(shí)現(xiàn)高性能HTTP客戶端

    C++ 實(shí)現(xiàn)高性能HTTP客戶端

    HttpClient可以實(shí)現(xiàn)所有HTTP的方法,通過API傳輸接收HTTP消息。本文詳細(xì)講解了HttpClient,以及如何運(yùn)用C++實(shí)現(xiàn)HTTP客戶端,感興趣的朋友可以參考一下
    2021-08-08
  • map插入自定義對象總結(jié)

    map插入自定義對象總結(jié)

    黑樹在插入節(jié)點(diǎn)時(shí),必須依照大小比對之后在一個(gè)合適的位置上執(zhí)行插入動作。所以作為關(guān)鍵字,起碼必須有“<”這個(gè)比較操作符
    2013-09-09
  • C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼

    C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++ 設(shè)置和獲取當(dāng)前工作路徑的實(shí)現(xiàn)代碼,防止DLL加載不到配置和文件,需要的朋友可以參考下
    2017-09-09

最新評論