mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-26 10:32:56 +01:00
#3019: ObjectPool wait on borrow condition fix
This commit is contained in:
@@ -47,7 +47,7 @@ public:
|
|||||||
{
|
{
|
||||||
return new C;
|
return new C;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateObject(P pObject)
|
bool validateObject(P pObject)
|
||||||
/// Checks whether the object is still valid
|
/// Checks whether the object is still valid
|
||||||
/// and can be reused.
|
/// and can be reused.
|
||||||
@@ -60,14 +60,14 @@ public:
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void activateObject(P pObject)
|
void activateObject(P pObject)
|
||||||
/// Called before an object is handed out by the pool.
|
/// Called before an object is handed out by the pool.
|
||||||
/// Also called for newly created objects, before
|
/// Also called for newly created objects, before
|
||||||
/// they are given out for the first time.
|
/// they are given out for the first time.
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivateObject(P pObject)
|
void deactivateObject(P pObject)
|
||||||
/// Called after an object has been given back to the
|
/// Called after an object has been given back to the
|
||||||
/// pool and the object is still valid (a prior call
|
/// pool and the object is still valid (a prior call
|
||||||
@@ -77,7 +77,7 @@ public:
|
|||||||
/// must not throw an exception.
|
/// must not throw an exception.
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyObject(P pObject)
|
void destroyObject(P pObject)
|
||||||
/// Destroy an object.
|
/// Destroy an object.
|
||||||
///
|
///
|
||||||
@@ -97,20 +97,20 @@ public:
|
|||||||
{
|
{
|
||||||
return new C;
|
return new C;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateObject(Poco::AutoPtr<C> pObject)
|
bool validateObject(Poco::AutoPtr<C> pObject)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void activateObject(Poco::AutoPtr<C> pObject)
|
void activateObject(Poco::AutoPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivateObject(Poco::AutoPtr<C> pObject)
|
void deactivateObject(Poco::AutoPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyObject(Poco::AutoPtr<C> pObject)
|
void destroyObject(Poco::AutoPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -125,20 +125,20 @@ public:
|
|||||||
{
|
{
|
||||||
return new C;
|
return new C;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validateObject(Poco::SharedPtr<C> pObject)
|
bool validateObject(Poco::SharedPtr<C> pObject)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void activateObject(Poco::SharedPtr<C> pObject)
|
void activateObject(Poco::SharedPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivateObject(Poco::SharedPtr<C> pObject)
|
void deactivateObject(Poco::SharedPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyObject(Poco::SharedPtr<C> pObject)
|
void destroyObject(Poco::SharedPtr<C> pObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ public:
|
|||||||
{
|
{
|
||||||
poco_assert (capacity <= peakCapacity);
|
poco_assert (capacity <= peakCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPool(const F& factory, std::size_t capacity, std::size_t peakCapacity):
|
ObjectPool(const F& factory, std::size_t capacity, std::size_t peakCapacity):
|
||||||
/// Creates a new ObjectPool with the given PoolableObjectFactory,
|
/// Creates a new ObjectPool with the given PoolableObjectFactory,
|
||||||
/// capacity and peak capacity. The PoolableObjectFactory must have
|
/// capacity and peak capacity. The PoolableObjectFactory must have
|
||||||
@@ -189,7 +189,7 @@ public:
|
|||||||
{
|
{
|
||||||
poco_assert (capacity <= peakCapacity);
|
poco_assert (capacity <= peakCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ObjectPool()
|
~ObjectPool()
|
||||||
/// Destroys the ObjectPool.
|
/// Destroys the ObjectPool.
|
||||||
{
|
{
|
||||||
@@ -205,7 +205,7 @@ public:
|
|||||||
poco_unexpected();
|
poco_unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P borrowObject(long timeoutMilliseconds = 0)
|
P borrowObject(long timeoutMilliseconds = 0)
|
||||||
/// Obtains an object from the pool, or creates a new object if
|
/// Obtains an object from the pool, or creates a new object if
|
||||||
/// possible.
|
/// possible.
|
||||||
@@ -217,22 +217,15 @@ public:
|
|||||||
{
|
{
|
||||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||||
|
|
||||||
if (!_pool.empty())
|
if (_size >= _peakCapacity && _pool.empty())
|
||||||
{
|
|
||||||
P pObject = _pool.back();
|
|
||||||
_pool.pop_back();
|
|
||||||
return activateObject(pObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_size >= _peakCapacity)
|
|
||||||
{
|
{
|
||||||
if (timeoutMilliseconds == 0)
|
if (timeoutMilliseconds == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
while (_size >= _peakCapacity)
|
while (_size >= _peakCapacity && _pool.empty())
|
||||||
{
|
{
|
||||||
if ( !_availableCondition.tryWait(_mutex, timeoutMilliseconds))
|
if (!_availableCondition.tryWait(_mutex, timeoutMilliseconds))
|
||||||
{
|
{
|
||||||
// timeout
|
// timeout
|
||||||
return 0;
|
return 0;
|
||||||
@@ -240,10 +233,19 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_pool.empty())
|
||||||
|
{
|
||||||
|
P pObject = _pool.back();
|
||||||
|
_pool.pop_back();
|
||||||
|
|
||||||
|
return activateObject(pObject);
|
||||||
|
}
|
||||||
|
|
||||||
// _size < _peakCapacity
|
// _size < _peakCapacity
|
||||||
P pObject = _factory.createObject();
|
P pObject = _factory.createObject();
|
||||||
activateObject(pObject);
|
activateObject(pObject);
|
||||||
_size++;
|
_size++;
|
||||||
|
|
||||||
return pObject;
|
return pObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,6 +262,7 @@ public:
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_pool.push_back(pObject);
|
_pool.push_back(pObject);
|
||||||
|
_availableCondition.signal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@@ -276,19 +279,19 @@ public:
|
|||||||
{
|
{
|
||||||
return _capacity;
|
return _capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t peakCapacity() const
|
std::size_t peakCapacity() const
|
||||||
{
|
{
|
||||||
return _peakCapacity;
|
return _peakCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t size() const
|
std::size_t size() const
|
||||||
{
|
{
|
||||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||||
|
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t available() const
|
std::size_t available() const
|
||||||
{
|
{
|
||||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||||
@@ -310,12 +313,12 @@ protected:
|
|||||||
}
|
}
|
||||||
return pObject;
|
return pObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ObjectPool();
|
ObjectPool();
|
||||||
ObjectPool(const ObjectPool&);
|
ObjectPool(const ObjectPool&);
|
||||||
ObjectPool& operator = (const ObjectPool&);
|
ObjectPool& operator = (const ObjectPool&);
|
||||||
|
|
||||||
F _factory;
|
F _factory;
|
||||||
std::size_t _capacity;
|
std::size_t _capacity;
|
||||||
std::size_t _peakCapacity;
|
std::size_t _peakCapacity;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "CppUnit/TestSuite.h"
|
#include "CppUnit/TestSuite.h"
|
||||||
#include "Poco/ObjectPool.h"
|
#include "Poco/ObjectPool.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
|
#include "Poco/Thread.h"
|
||||||
|
|
||||||
|
|
||||||
using Poco::ObjectPool;
|
using Poco::ObjectPool;
|
||||||
@@ -30,18 +31,18 @@ ObjectPoolTest::~ObjectPoolTest()
|
|||||||
|
|
||||||
void ObjectPoolTest::testObjectPool()
|
void ObjectPoolTest::testObjectPool()
|
||||||
{
|
{
|
||||||
ObjectPool<std::string, Poco::SharedPtr<std::string> > pool(3, 4);
|
ObjectPool<std::string, Poco::SharedPtr<std::string>> pool(3, 4);
|
||||||
|
|
||||||
assertTrue (pool.capacity() == 3);
|
assertTrue (pool.capacity() == 3);
|
||||||
assertTrue (pool.peakCapacity() == 4);
|
assertTrue (pool.peakCapacity() == 4);
|
||||||
assertTrue (pool.size() == 0);
|
assertTrue (pool.size() == 0);
|
||||||
assertTrue (pool.available() == 4);
|
assertTrue (pool.available() == 4);
|
||||||
|
|
||||||
Poco::SharedPtr<std::string> pStr1 = pool.borrowObject();
|
Poco::SharedPtr<std::string> pStr1 = pool.borrowObject();
|
||||||
pStr1->assign("first");
|
pStr1->assign("first");
|
||||||
assertTrue (pool.size() == 1);
|
assertTrue (pool.size() == 1);
|
||||||
assertTrue (pool.available() == 3);
|
assertTrue (pool.available() == 3);
|
||||||
|
|
||||||
Poco::SharedPtr<std::string> pStr2 = pool.borrowObject();
|
Poco::SharedPtr<std::string> pStr2 = pool.borrowObject();
|
||||||
pStr2->assign("second");
|
pStr2->assign("second");
|
||||||
assertTrue (pool.size() == 2);
|
assertTrue (pool.size() == 2);
|
||||||
@@ -51,19 +52,19 @@ void ObjectPoolTest::testObjectPool()
|
|||||||
pStr3->assign("third");
|
pStr3->assign("third");
|
||||||
assertTrue (pool.size() == 3);
|
assertTrue (pool.size() == 3);
|
||||||
assertTrue (pool.available() == 1);
|
assertTrue (pool.available() == 1);
|
||||||
|
|
||||||
Poco::SharedPtr<std::string> pStr4 = pool.borrowObject();
|
Poco::SharedPtr<std::string> pStr4 = pool.borrowObject();
|
||||||
pStr4->assign("fourth");
|
pStr4->assign("fourth");
|
||||||
assertTrue (pool.size() == 4);
|
assertTrue (pool.size() == 4);
|
||||||
assertTrue (pool.available() == 0);
|
assertTrue (pool.available() == 0);
|
||||||
|
|
||||||
Poco::SharedPtr<std::string> pStr5 = pool.borrowObject();
|
Poco::SharedPtr<std::string> pStr5 = pool.borrowObject();
|
||||||
assertTrue (pStr5.isNull());
|
assertTrue (pStr5.isNull());
|
||||||
|
|
||||||
pool.returnObject(pStr4);
|
pool.returnObject(pStr4);
|
||||||
assertTrue (pool.size() == 4);
|
assertTrue (pool.size() == 4);
|
||||||
assertTrue (pool.available() == 1);
|
assertTrue (pool.available() == 1);
|
||||||
|
|
||||||
pool.returnObject(pStr3);
|
pool.returnObject(pStr3);
|
||||||
assertTrue (pool.size() == 4);
|
assertTrue (pool.size() == 4);
|
||||||
assertTrue (pool.available() == 2);
|
assertTrue (pool.available() == 2);
|
||||||
@@ -75,10 +76,10 @@ void ObjectPoolTest::testObjectPool()
|
|||||||
pool.returnObject(pStr3);
|
pool.returnObject(pStr3);
|
||||||
pool.returnObject(pStr2);
|
pool.returnObject(pStr2);
|
||||||
pool.returnObject(pStr1);
|
pool.returnObject(pStr1);
|
||||||
|
|
||||||
assertTrue (pool.size() == 3);
|
assertTrue (pool.size() == 3);
|
||||||
assertTrue (pool.available() == 4);
|
assertTrue (pool.available() == 4);
|
||||||
|
|
||||||
pStr1 = pool.borrowObject();
|
pStr1 = pool.borrowObject();
|
||||||
assertTrue (*pStr1 == "second");
|
assertTrue (*pStr1 == "second");
|
||||||
assertTrue (pool.available() == 3);
|
assertTrue (pool.available() == 3);
|
||||||
@@ -88,6 +89,27 @@ void ObjectPoolTest::testObjectPool()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ObjectPoolTest::testObjectPoolWaitOnBorrowObject()
|
||||||
|
{
|
||||||
|
ObjectPool<std::string, Poco::SharedPtr<std::string>> pool(1, 1);
|
||||||
|
|
||||||
|
Poco::SharedPtr<std::string> objectToReturnDuringBorrow = pool.borrowObject();
|
||||||
|
|
||||||
|
Poco::Thread threadToReturnObject;
|
||||||
|
threadToReturnObject.startFunc(
|
||||||
|
[&pool, &objectToReturnDuringBorrow]()
|
||||||
|
{
|
||||||
|
pool.returnObject(objectToReturnDuringBorrow);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Poco::SharedPtr<std::string> object = pool.borrowObject(1000);
|
||||||
|
|
||||||
|
threadToReturnObject.join();
|
||||||
|
assertFalse(object.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ObjectPoolTest::setUp()
|
void ObjectPoolTest::setUp()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -103,6 +125,7 @@ CppUnit::Test* ObjectPoolTest::suite()
|
|||||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ObjectPoolTest");
|
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ObjectPoolTest");
|
||||||
|
|
||||||
CppUnit_addTest(pSuite, ObjectPoolTest, testObjectPool);
|
CppUnit_addTest(pSuite, ObjectPoolTest, testObjectPool);
|
||||||
|
CppUnit_addTest(pSuite, ObjectPoolTest, testObjectPoolWaitOnBorrowObject);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
~ObjectPoolTest();
|
~ObjectPoolTest();
|
||||||
|
|
||||||
void testObjectPool();
|
void testObjectPool();
|
||||||
|
void testObjectPoolWaitOnBorrowObject();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|||||||
Reference in New Issue
Block a user