溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++如何實現對象池

發布時間:2022-01-22 13:53:53 來源:億速云 閱讀:397 作者:小新 欄目:開發技術

這篇“C++如何實現對象池”文章,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要參考一下,對于“C++如何實現對象池”,小編整理了以下知識點,請大家跟著小編的步伐一步一步的慢慢理解,接下來就讓我們進入主題吧。

    前言

    需求無限,但資源有限的情況下,就需要對資源進行專門的管理。不斷的申請和釋放內存是不合理的,會造成內存的波動,以及內存不受限的增長。比如,實現了一個消息隊列,當發消息的速度快于處理消息的速度時,如果不對資源進行控制,就會導致內存不斷的增長。除非有專門的內存管理機制,或明確的編譯器優化內存復用,否則建立一個資源管理模塊是很有必要的。對象池就是一個對限定數量資源復用管理的模塊。

    一、什么是對象池

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

    二、如何實現

    1.確定接口

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

    C++如何實現對象池

    (2)、確定靜態關系
    根據上面的序列圖確定的接口繪制成類圖,如下:

    C++如何實現對象池

    2.轉成代碼

    由于模塊規模小,接口也不多,所以就不展示進一步細化設計了。因為本文講述的是C++實現對象池,所以將上述設計轉化為C++接口定義。如下:

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

    三、完整代碼

    根據上述的初步設計,再進行細化,以及實現,最終得出如下代碼實現。
    ObjectPool.h

    #ifndef OBJECTPOOL_H
    #define OBJECTPOOL_H
    /************************************************************************
    * @Project:  	AC::ObjectPool
    * @Decription:  對象池:“需求很大,但數量有限”的情況下,就需要對資源進行專門的管理,
    *不斷的申請和釋放對象是不合理的(除非有專門的內存管理機制,或明確的編譯優化內存復用)。
    *這是一個對限定數量資源的復用管理模塊。
    * @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>
    		/// 構造方法
    		/// </summary>
    		/// <param name="bufferArray">對象池的緩沖區,由外部指定,可以理解為一個數組。數組大小需滿足bufferSize>=elementSize*arraySize</param>
    		/// <param name="elementSize">數組元素大小</param>
    		/// <param name="arraySize">數組長度或元素個數</param>
    		ObjectPool(void* bufferArray, int elementSize, int arraySize );
    		/// <summary>
    		/// 析構方法
    		/// </summary>
    		~ObjectPool();
    		/// <summary>
    		/// 申請對象
    		/// 如果池里對象不足,則會等待,直到有對象才返回。
    		/// </summary>
    		/// <returns>返回申請的對象指針</returns>
    		void* Applicate();
    		/// <summary>
    		/// 申請對象
    		/// </summary>
    		/// <param name="timeout">超時時間,超時后返回null</param>
    		/// <returns>返回申請的對象指針</returns>
    		void* Applicate(int timeout);	
    		/// <summary>
    		/// 歸還對象
    		/// </summary>
    		/// <param name="element">需歸還的對象</param>
    		void ReturnBack(void* element);	
    		/// <summary>
    		/// 獲取對象池的緩沖區,即構造方法中的bufferArray
    		/// </summary>
    		/// <returns>緩沖區的指針</returns>
    		void* GetPoolBuffer();
    		/// <summary>
    		/// 獲取對象的大小,即構造方法中的elementSize
    		/// </summary>
    		/// <returns>對象的大小</returns>
    		int GetObjectSize();
    		/// <summary>
    		/// 獲取總的對象數量,即構造方法中的arraySize
    		/// </summary>
    		/// <returns>總的對象數量</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>
    		/// 構造方法
    		/// </summary>
    		/// <param name="array">對象數組</param>
    		/// <param name="size">數組大小</param>
    		/// <returns></returns>
    		ObjectPoolGeneric(T*array,int size) :ObjectPool(array, sizeof(T), size)
    		{
    		}
    		/// <summary>
    		/// 析構方法
    		/// </summary>
    		~ObjectPoolGeneric() {}
    		/// <summary>
    		/// 申請對象
    		/// 如果池里對象不足,則會等待,直到有對象才返回。
    		/// </summary>
    		/// <returns>返回申請的對象指針</returns>
    		T* Applicate() {
    			return (T*)ObjectPool::Applicate();
    		}
    		/// <summary>
    		/// 申請對象
    		/// </summary>
    		/// <param name="timeout">超時時間,超時后返回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>
    		/// 獲取對象池的緩沖區,即構造方法中的bufferArray
    		/// </summary>
    		/// <returns>緩沖區的指針</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、對象復用,示例:

    #include "ObjectPool.h"
    class A {
    public:
    	A() {
    		printf("%p\n", this);
    	}
    };
    int main(int argc, char** argv) {
    	//初始化對象池,2個對象
    	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();
    	//使用結束,刪除緩存
    	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;
    };
    //線程信息數組,數組長度即線程池的線程數
    ThreadInfo _threadArray[3];
    //對象池,使用線程信息數組初始化
    AC::ObjectPoolGeneric<ThreadInfo>_threadPool(_threadArray, 3);
    bool _exitThreadPool = false;
    //在線程池中運行方法
    void RunInThreadPool(std::function<void()> f) {
    	//申請線程
    	auto threadInfo = _threadPool.Applicate();
    	threadInfo->_threadPoc = f; 
    	if (threadInfo->pThread)
    		//復用線程
    	{
    		threadInfo->_cv.notify_one();
    	}
    	else
    		//創建線程
    	{
    		threadInfo->pThread = new std::thread([=]() {
    			while (!_exitThreadPool)
    			{
    				printf("thread %d run\n", threadInfo->pThread->get_id());
    				if (threadInfo->_threadPoc)
    				{	//執行線程操作
    					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)
    	{   //在線程池中運行方法
    		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
    &hellip;

    以上是“C++如何實現對象池”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    c++
    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女