VAObjectPool.cpp 6.55 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 *  --------------------------------------------------------------------------------------------
 *
 *    VVV        VVV A           Virtual Acoustics (VA) | http://www.virtualacoustics.org
 *     VVV      VVV AAA          Licensed under the Apache License, Version 2.0
 *      VVV    VVV   AAA
 *       VVV  VVV     AAA        Copyright 2015-2017
 *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
 *         VVVV         AAA      RWTH Aachen University
 *
 *  --------------------------------------------------------------------------------------------
 */

14
15
#include <VAObjectPool.h>
#include <VAPoolObject.h>
Jonas Stienen's avatar
Jonas Stienen committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include "VALog.h"

#include <ITACriticalSection.h>

#include <assert.h>
#include <set>

// Debugging-Messages
#define POOL_DEBUG_MESSAGES 0

// Wiederverwendung von Pool-Objekten unterbinden (nur new/delete)
#define POOL_NO_REUSE 0

// ObjectPool class
31
32
class CVAObjectPool : public IVAObjectPool
{
Jonas Stienen's avatar
Jonas Stienen committed
33
34
35
36
37
38
39
40
41
42
43
public:
	// Konstruktor
	/**
	 * Erzeugt einen Pool mit der angegebenen Anzahl von Objekten.
	 * Der zweite Parameter legt die Vergrerung im Falle eines berlaufes fest.
	 *
	 * \param iInitialSize		Initiale Anzahl Objekte
	 * \param iDelta            Vergrerung wenn keine freien Objekte mehr
	 * \param pFactory			Factory zur Erzeugung der Pool-Objekte
	 * \param bDeleteFactory	bergebene Factory im Destruktor freigeben?
	 */
44
	CVAObjectPool( const int iInitialSize, const int iDelta, IVAPoolObjectFactory* pFactory, const bool bDeleteFactory );
Jonas Stienen's avatar
Jonas Stienen committed
45
46
47
48
49

	// Destruktor
	virtual ~CVAObjectPool();

	// Namen setzen (frs Debugging)
50
	void SetName( const std::string& sName );
Jonas Stienen's avatar
Jonas Stienen committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

	// Zurcksetzen. Setzt alle Objekte auf unbenutzt. ndert die Pool-Gre nicht.
	void Reset();

	// Anzahl der freien Objekte zurckgeben
	int GetNumFree() const;

	// Anzahl der benutzten Objekte zurckgeben
	int GetNumUsed() const;

	// Anzahl der Objekte (insgesamt) zurckgeben
	int GetSize() const;

	// Anzahl der (freien) Objekte vergrern
	// (Rckgabe: Anzahl der erzeugten Elemente)
66
	int Grow( const int iDelta );
Jonas Stienen's avatar
Jonas Stienen committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

	// Freies Objekt anfordern.
	// (Setzt den Referenzzhler des Objektes auf 1)
	CVAPoolObject* RequestObject();

private:
	// Alias Typen
	typedef std::set<CVAPoolObject*> ObjSet;
	typedef ObjSet::iterator ObjSetIt;
	typedef ObjSet::const_iterator ObjSetCit;

	std::string m_sName;
	int m_iDelta;
	IVAPoolObjectFactory* m_pFactory;
	bool m_bDeleteFactory;

	ITACriticalSection m_csLists;

	ObjSet m_sFree;  // Liste der freien Objekte
	ObjSet m_sUsed;  // Liste der sich in Benutzung befindlichen Objekte

	// Diese Methode darf nur von den Pool-Objekten aufgerufen werden,
	// wenn diese keine weiteren Referenzen mehr haben.
90
	void ReleaseObject( CVAPoolObject* pObject );
Jonas Stienen's avatar
Jonas Stienen committed
91
92
93
94
95
96
97
98

	friend class CVAPoolObject;
};


// -= Implementierung object pool =----------------------------------------------------------------

//! Factory method for ObjectPool interface
99
100
101
IVAObjectPool* IVAObjectPool::Create( int iInitialSize, int iDelta, IVAPoolObjectFactory* pFactory, bool bDeleteFactory )
{
	return new CVAObjectPool( iInitialSize, iDelta, pFactory, bDeleteFactory );
Jonas Stienen's avatar
Jonas Stienen committed
102
103
}

104
CVAObjectPool::CVAObjectPool( int iInitialSize, int iDelta, IVAPoolObjectFactory* pFactory, bool bDeleteFactory )
105
106
107
	: m_iDelta( iDelta )
	, m_pFactory( pFactory )
	, m_bDeleteFactory( bDeleteFactory )
Jonas Stienen's avatar
Jonas Stienen committed
108
109
{
	// Objekte vorerzeugen
110
	Grow( iInitialSize );
Jonas Stienen's avatar
Jonas Stienen committed
111
112
}

113
114
115
CVAObjectPool::~CVAObjectPool()
{
	ITACriticalSectionLock oLock( m_csLists );
Jonas Stienen's avatar
Jonas Stienen committed
116
117

	// Alle Objekte freigeben
118
119
120
121
122
	for( ObjSetIt it = m_sFree.begin(); it != m_sFree.end(); ++it )
		delete ( *it );

	for( ObjSetIt it = m_sUsed.begin(); it != m_sUsed.end(); ++it )
		delete ( *it );
Jonas Stienen's avatar
Jonas Stienen committed
123

124
125
	if( m_bDeleteFactory )
		delete m_pFactory;
Jonas Stienen's avatar
Jonas Stienen committed
126
127
};

128
129
void CVAObjectPool::SetName( const std::string& sName )
{
Jonas Stienen's avatar
Jonas Stienen committed
130
131
132
	m_sName = sName;
}

133
134
void CVAObjectPool::Reset()
{
Jonas Stienen's avatar
Jonas Stienen committed
135
	// Alle benutzten Objekte zurck in die Freiliste
136
137
138
139
140
	for( ObjSetIt it = m_sUsed.begin(); it != m_sUsed.end(); ++it )
	{
		( *it )->ResetReferences();
		( *it )->PreRelease();
		m_sFree.insert( *it );
Jonas Stienen's avatar
Jonas Stienen committed
141
142
143
144
	}
	m_sUsed.clear();
}

145
146
147
int CVAObjectPool::GetNumFree() const
{
	return ( int ) m_sFree.size();
Jonas Stienen's avatar
Jonas Stienen committed
148
149
}

150
151
152
int CVAObjectPool::GetNumUsed() const
{
	return ( int ) m_sUsed.size();
Jonas Stienen's avatar
Jonas Stienen committed
153
154
}

155
156
157
int CVAObjectPool::GetSize() const
{
	return ( int ) ( m_sFree.size() + m_sUsed.size() );
Jonas Stienen's avatar
Jonas Stienen committed
158
159
}

160
161
int CVAObjectPool::Grow( int iDelta )
{
162
	ITACriticalSectionLock oLock( m_csLists );
Jonas Stienen's avatar
Jonas Stienen committed
163

164
165
	for( int i = 0; i < iDelta; i++ )
	{
Jonas Stienen's avatar
Jonas Stienen committed
166
167
168
169
170
		CVAPoolObject* pObject = m_pFactory->CreatePoolObject();
		assert( pObject != nullptr );

		pObject->m_pParentPool = this;

171
		m_sFree.insert( pObject );
Jonas Stienen's avatar
Jonas Stienen committed
172
173
174
175
	}

	if( POOL_DEBUG_MESSAGES )
	{
176
		VA_VERBOSE( "ObjectPool" + m_sName, "Growing pool by " << iDelta << "." );
Jonas Stienen's avatar
Jonas Stienen committed
177
178
179
180
181
	}

	return iDelta;
}

182
183
CVAPoolObject* CVAObjectPool::RequestObject()
{
Jonas Stienen's avatar
Jonas Stienen committed
184
185
186
187
188
189
190
191
192
193
194
195

#if (POOL_NO_REUSE==1)

	// Direkte Implementierung mit new-operator (keine Wiederverwendung). Nur zum Debuggen.
	CVAPoolObject* pObject = m_pFactory->CreatePoolObject();
	pObject->pParentPool = this;
	pObject->AddReference();
	pObject->PreRequest();

#else

	// Lock auf Listen erzwingen
196
	ITACriticalSectionLock oLock( m_csLists );
Jonas Stienen's avatar
Jonas Stienen committed
197
198

	// Standard-Implementierung (mit Wiederverwendung)
199
200
201
	if( m_sFree.empty() )
	{
		Grow( m_iDelta );
202
		VA_TRACE( "ObjectPool", "Pool " << m_sName << " growing by " << m_iDelta << " objects required" );
203
	}
Jonas Stienen's avatar
Jonas Stienen committed
204
205

	assert( !m_sFree.empty() );
206
	CVAPoolObject* pObject = *( m_sFree.begin() );
Jonas Stienen's avatar
Jonas Stienen committed
207
208
	pObject->AddReference();

209
210
	m_sFree.erase( pObject );
	m_sUsed.insert( pObject );
Jonas Stienen's avatar
Jonas Stienen committed
211
212
213

	pObject->PreRequest();

214
#endif
Jonas Stienen's avatar
Jonas Stienen committed
215
216

#if (POOL_DEBUG_MESSAGES==1)
217
	VA_DEBUG_PRINTF("[ObjectPool \"%s\" 0x%08Xh] Requested object 0x%08Xh (%d free, %d used, %d total)\n", m_sName.c_str(), this, pObject, GetNumFree(), GetNumUsed(), GetSize());
Jonas Stienen's avatar
Jonas Stienen committed
218
219
220
221
222
#endif

	return pObject;
}

223
224
void CVAObjectPool::ReleaseObject( CVAPoolObject* pObject )
{
Jonas Stienen's avatar
Jonas Stienen committed
225
226
227
228
229
230
231
232
233
234
235
236
237
	// Wichtig: ReleaseObjekt wird von den PoolObjekten aufrufen, wenn diese KEINE Referenzen mehr haben!
	assert( pObject->GetNumReferences() == 0 );

	pObject->PreRelease();

#if (POOL_NO_REUSE==1)

	// Direkte Implementierung mit delete-operator (keine Wiederverwendung). Nur zum Debuggen.
	delete pObject;

#else

	// Lock auf Listen erzwingen
238
	ITACriticalSectionLock oLock( m_csLists );
Jonas Stienen's avatar
Jonas Stienen committed
239
240
241
242
243
244

	// Standard-Implementierung (mit Wiederverwendung)

	// Keine Referenzen mehr => Objekt wieder freigeben

	// Sicherheitscheck: Rckgabe = Anzahl gelschter Objekte
245
	int nDeleted = ( int ) m_sUsed.erase( pObject );
Jonas Stienen's avatar
Jonas Stienen committed
246
247
	// TODO: Wichtig. Referenz-Management fr Container beim Reset handhaben
	// assert( nDeleted == 1 );
248
	m_sFree.insert( pObject );
Jonas Stienen's avatar
Jonas Stienen committed
249
250
251
#endif // POOL_NO_REUSE

#if (POOL_DEBUG_MESSAGES==1)
252
	VA_DEBUG_PRINTF( "[CVAObjectPool \"%s\" 0x%08Xh] Released object 0x%08Xh (%d free, %d used, %d total)\n", m_sName.c_str(), this, pObject, GetNumFree(), GetNumUsed(), GetSize() );
Jonas Stienen's avatar
Jonas Stienen committed
253
254
#endif
}