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

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

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

前言

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

一、什么是對(duì)象池

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

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

1.確定接口

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

在這里插入圖片描述

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

在這里插入圖片描述

2.轉(zhuǎn)成代碼

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

    /// <summary>
	/// 對(duì)象池
	/// </summary>
	class ObjectPool
	{
	public:		
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="bufferArray">對(duì)象池的緩沖區(qū),由外部指定,可以理解為一個(gè)數(shù)組。數(shù)組大小需滿足bufferSize>=elementSize*arraySize</param>
		/// <param name="elementSize">數(shù)組元素大小</param>
		/// <param name="arraySize">數(shù)組長(zhǎng)度或元素個(gè)數(shù)</param>
		ObjectPool(void* bufferArray, int elementSize, int arraySize );		
		/// <summary>
		/// 申請(qǐng)對(duì)象
		/// 如果池里對(duì)象不足,則會(huì)等待,直到有對(duì)象才返回。
		/// </summary>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		void* Applicate();
		/// <summary>
		/// 申請(qǐng)對(duì)象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		void* Applicate(int timeout);	
		/// <summary>
		/// 歸還對(duì)象
		/// </summary>
		/// <param name="element">需歸還的對(duì)象</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:  對(duì)象池:“需求很大,但數(shù)量有限”的情況下,就需要對(duì)資源進(jìn)行專門(mén)的管理,
*不斷的申請(qǐng)和釋放對(duì)象是不合理的(除非有專門(mén)的內(nèi)存管理機(jī)制,或明確的編譯優(yōu)化內(nèi)存復(fù)用)。
*這是一個(gè)對(duì)限定數(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>
	/// 對(duì)象池
	/// </summary>
	class ObjectPool
	{
	public:		
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="bufferArray">對(duì)象池的緩沖區(qū),由外部指定,可以理解為一個(gè)數(shù)組。數(shù)組大小需滿足bufferSize>=elementSize*arraySize</param>
		/// <param name="elementSize">數(shù)組元素大小</param>
		/// <param name="arraySize">數(shù)組長(zhǎng)度或元素個(gè)數(shù)</param>
		ObjectPool(void* bufferArray, int elementSize, int arraySize );
		/// <summary>
		/// 析構(gòu)方法
		/// </summary>
		~ObjectPool();
		/// <summary>
		/// 申請(qǐng)對(duì)象
		/// 如果池里對(duì)象不足,則會(huì)等待,直到有對(duì)象才返回。
		/// </summary>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		void* Applicate();
		/// <summary>
		/// 申請(qǐng)對(duì)象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		void* Applicate(int timeout);	
		/// <summary>
		/// 歸還對(duì)象
		/// </summary>
		/// <param name="element">需歸還的對(duì)象</param>
		void ReturnBack(void* element);	
		/// <summary>
		/// 獲取對(duì)象池的緩沖區(qū),即構(gòu)造方法中的bufferArray
		/// </summary>
		/// <returns>緩沖區(qū)的指針</returns>
		void* GetPoolBuffer();
		/// <summary>
		/// 獲取對(duì)象的大小,即構(gòu)造方法中的elementSize
		/// </summary>
		/// <returns>對(duì)象的大小</returns>
		int GetObjectSize();
		/// <summary>
		/// 獲取總的對(duì)象數(shù)量,即構(gòu)造方法中的arraySize
		/// </summary>
		/// <returns>總的對(duì)象數(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>
	/// 泛型對(duì)象池
	/// </summary>
	/// <typeparam name="T">對(duì)象類型</typeparam>
	template<typename T>
	class ObjectPoolGeneric:private ObjectPool
	{
	public:
		/// <summary>
		/// 構(gòu)造方法
		/// </summary>
		/// <param name="array">對(duì)象數(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>
		/// 申請(qǐng)對(duì)象
		/// 如果池里對(duì)象不足,則會(huì)等待,直到有對(duì)象才返回。
		/// </summary>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		T* Applicate() {
			return (T*)ObjectPool::Applicate();
		}
		/// <summary>
		/// 申請(qǐng)對(duì)象
		/// </summary>
		/// <param name="timeout">超時(shí)時(shí)間,超時(shí)后返回null</param>
		/// <returns>返回申請(qǐng)的對(duì)象指針</returns>
		T* Applicate(int timeout) {
			return (T*)ObjectPool::Applicate(timeout);
		}
		/// <summary>
		/// 歸還對(duì)象
		/// </summary>
		/// <param name="element">需歸還的對(duì)象</param>
		void ReturnBack(T* element)
		{
			ObjectPool::ReturnBack(element);
		}
		/// <summary>
		/// 獲取對(duì)象池的緩沖區(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、對(duì)象復(fù)用,示例:

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

輸出:
016502E9
016502E8
016502E9

2、簡(jiǎn)易的線程池,示例:

#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ù)組長(zhǎng)度即線程池的線程數(shù)
ThreadInfo _threadArray[3];
//對(duì)象池,使用線程信息數(shù)組初始化
AC::ObjectPoolGeneric<ThreadInfo>_threadPool(_threadArray, 3);
bool _exitThreadPool = false;
//在線程池中運(yùn)行方法
void RunInThreadPool(std::function<void()> f) {
	//申請(qǐng)線程
	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)容,本文介紹了對(duì)象池的設(shè)計(jì)與實(shí)現(xiàn)以及使用,其使用場(chǎng)景其實(shí)不算多,因?yàn)楹芏嘈枰獙?duì)象復(fù)用的場(chǎng)景通常以及有底層實(shí)現(xiàn)了,比如線程池?cái)?shù)據(jù)庫(kù)的連接池等,所以本文講的內(nèi)容只能適用于少數(shù)的場(chǎng)景,比如waveOut播放音頻時(shí)是可以使用對(duì)象池實(shí)現(xiàn) 的。但總得來(lái)說(shuō),對(duì)象池還是有用的,所以將其寫(xiě)成博客用于記錄曾經(jīng)用過(guò)的技術(shù)。

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    黑樹(shù)在插入節(jié)點(diǎn)時(shí),必須依照大小比對(duì)之后在一個(gè)合適的位置上執(zhí)行插入動(dòng)作。所以作為關(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

最新評(píng)論