summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2021-10-16 12:58:38 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2021-10-16 13:01:31 +0100
commit016175ea3992a796142d58a3df17a06bd7a7a256 (patch)
tree7727f6ce234bf889910c7749f5a20a36f348a457
parent<type_traits> needed for std::is_member_function_pointer_v (diff)
downloadlibadhocutil-0.8.7.tar.bz2
libadhocutil-0.8.7.tar.xz
libadhocutil-0.8.7.zip
Refactored semaphore/resource poollibadhocutil-0.8.7
-rw-r--r--libadhocutil/polyfill-semaphore.h1
-rw-r--r--libadhocutil/resourcePool.cpp30
-rw-r--r--libadhocutil/resourcePool.h55
-rw-r--r--libadhocutil/resourcePool.impl.h31
-rw-r--r--libadhocutil/unittests/testResourcePool.cpp30
5 files changed, 75 insertions, 72 deletions
diff --git a/libadhocutil/polyfill-semaphore.h b/libadhocutil/polyfill-semaphore.h
index 273d0ec..9279b26 100644
--- a/libadhocutil/polyfill-semaphore.h
+++ b/libadhocutil/polyfill-semaphore.h
@@ -5,6 +5,7 @@
// http://stackoverflow.com/questions/4792449/c0x-has-no-semaphores-how-to-synchronize-threads
#include "visibility.h"
+#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <mutex>
diff --git a/libadhocutil/resourcePool.cpp b/libadhocutil/resourcePool.cpp
index cc2cec0..5e9bbb0 100644
--- a/libadhocutil/resourcePool.cpp
+++ b/libadhocutil/resourcePool.cpp
@@ -1,7 +1,37 @@
#include "resourcePool.h"
#include "compileTimeFormatter.h"
+#ifdef __cpp_lib_semaphore
+# include <semaphore>
+#else
+# include "polyfill-semaphore.h"
+#endif
namespace AdHoc {
+ ResourcePoolBase::ResourcePoolBase(std::ptrdiff_t maxSize, std::size_t keep_) :
+ keep {keep_}, poolSize {std::make_unique<SemaphoreType>(maxSize)}
+ {
+ }
+
+ void
+ ResourcePoolBase::release()
+ {
+ poolSize->release();
+ }
+
+ void
+ ResourcePoolBase::acquire()
+ {
+ poolSize->acquire();
+ }
+
+ bool
+ ResourcePoolBase::try_acquire_for(std::chrono::milliseconds timeout)
+ {
+ return poolSize->try_acquire_for(timeout);
+ }
+
+ ResourcePoolBase::~ResourcePoolBase() = default;
+
TimeOutOnResourcePool::TimeOutOnResourcePool(const char * const n) : name(n) { }
AdHocFormatter(TimeOutOnResourcePoolMsg, "Timeout getting a resource from pool of %?");
diff --git a/libadhocutil/resourcePool.h b/libadhocutil/resourcePool.h
index 2fcaf6b..1a29dc9 100644
--- a/libadhocutil/resourcePool.h
+++ b/libadhocutil/resourcePool.h
@@ -5,10 +5,9 @@
#include "exception.h"
#ifdef __cpp_lib_semaphore
# include <semaphore>
-#else
-# include "polyfill-semaphore.h"
#endif
#include "visibility.h"
+#include <chrono>
#include <cstddef>
#include <list>
#include <map>
@@ -17,13 +16,9 @@
#include <string>
#include <thread>
#include <tuple>
+// IWYU pragma: no_include "polyfill-semaphore.h"
namespace AdHoc {
-#ifdef __cpp_lib_semaphore
- using SemaphoreType = std::counting_semaphore<>;
-#else
- using SemaphoreType = Semaphore;
-#endif
template<typename Resource> class ResourcePool;
/// A handle to a resource allocated from a ResourcePool.
@@ -59,20 +54,45 @@ namespace AdHoc {
std::shared_ptr<Object> resource;
};
+ class DLL_PUBLIC ResourcePoolBase {
+ public:
+ /// Create a new resource pool.
+ /// @param maxSize The upper limit of how many concurrent active resources there can be.
+ /// @param keep The number of resources to cache for reuse.
+ ResourcePoolBase(std::ptrdiff_t maxSize, std::size_t keep);
+ virtual ~ResourcePoolBase();
+
+ /// Standard move/copy support
+ SPECIAL_MEMBERS_DELETE(ResourcePoolBase);
+
+ void acquire();
+ bool try_acquire_for(std::chrono::milliseconds);
+ void release();
+
+#ifdef __cpp_lib_semaphore
+ using SemaphoreType = std::counting_semaphore<>;
+#else
+ using SemaphoreType = class Semaphore;
+#endif
+ protected:
+ mutable std::shared_mutex lock;
+ std::size_t keep;
+
+ private:
+ std::unique_ptr<SemaphoreType> poolSize;
+ };
+
/// A fully featured resource pool for sharing and reusing a finite set of
/// resources, possibly across multiple threads.
- template<typename Resource> class DLL_PUBLIC ResourcePool {
+ template<typename Resource> class DLL_PUBLIC ResourcePool : ResourcePoolBase {
public:
friend class ResourceHandle<Resource>;
- /// Create a new resource pool.
- /// @param maxSize The upper limit of how many concurrent active resources there can be.
- /// @param keep The number of resources to cache for reuse.
- ResourcePool(std::ptrdiff_t maxSize, std::size_t keep);
- virtual ~ResourcePool();
+ using ResourcePoolBase::ResourcePoolBase;
+ ~ResourcePool() override;
/// Standard move/copy support
- SPECIAL_MEMBERS_DEFAULT_MOVE_NO_COPY(ResourcePool);
+ SPECIAL_MEMBERS_DELETE(ResourcePool);
/// Get a resource from the pool (maybe cached, maybe constructed afresh)
ResourceHandle<Resource> get();
@@ -91,10 +111,6 @@ namespace AdHoc {
std::size_t inUseCount() const;
/// Get number of available cached resources.
std::size_t availableCount() const;
-#ifndef __cpp_lib_semaphore
- /// Get number of free slots.
- std::ptrdiff_t freeCount() const;
-#endif
protected:
/// Create a new resource instance to add to the pool.
@@ -114,9 +130,6 @@ namespace AdHoc {
DLL_PRIVATE static void removeFrom(const std::shared_ptr<Resource> &, InUse &);
DLL_PRIVATE ResourceHandle<Resource> getOne();
- mutable std::shared_mutex lock;
- SemaphoreType poolSize;
- std::size_t keep;
Available available;
InUse inUse;
};
diff --git a/libadhocutil/resourcePool.impl.h b/libadhocutil/resourcePool.impl.h
index e1791be..f2a62b4 100644
--- a/libadhocutil/resourcePool.impl.h
+++ b/libadhocutil/resourcePool.impl.h
@@ -4,12 +4,8 @@
#include "lockHelpers.h"
#include "resourcePool.h" // IWYU pragma: export
#include "safeMapFind.h"
-#ifdef __cpp_lib_semaphore
-# include <semaphore>
-#else
-# include "polyfill-semaphore.h"
-#endif
#include <boost/assert.hpp>
+#include <chrono>
#include <cstddef>
#include <exception>
#include <memory>
@@ -118,9 +114,6 @@ namespace AdHoc {
//
// ResourcePool
//
-
- template<typename R> ResourcePool<R>::ResourcePool(std::ptrdiff_t max, std::size_t k) : poolSize(max), keep(k) { }
-
template<typename R> ResourcePool<R>::~ResourcePool()
{
for (auto & r : inUse) {
@@ -156,16 +149,6 @@ namespace AdHoc {
return available.size();
}
-#ifndef __cpp_lib_semaphore
- template<typename R>
- std::ptrdiff_t
- ResourcePool<R>::freeCount() const
- {
- SharedLock(lock);
- return poolSize.freeCount();
- }
-#endif
-
template<typename R>
ResourceHandle<R>
ResourcePool<R>::getMine()
@@ -186,12 +169,12 @@ namespace AdHoc {
ResourceHandle<R>
ResourcePool<R>::get()
{
- poolSize.acquire();
+ acquire();
try {
return ResourceHandle(getOne());
}
catch (...) {
- poolSize.release();
+ release();
throw;
}
}
@@ -200,14 +183,14 @@ namespace AdHoc {
ResourceHandle<R>
ResourcePool<R>::get(const std::chrono::milliseconds timeout)
{
- if (!poolSize.try_acquire_for(timeout)) {
+ if (!try_acquire_for(timeout)) {
throw TimeOutOnResourcePoolT<R>();
}
try {
return getOne();
}
catch (...) {
- poolSize.release();
+ release();
throw;
}
}
@@ -256,7 +239,7 @@ namespace AdHoc {
}
catch (...) {
}
- poolSize.release();
+ release();
}
template<typename R>
@@ -265,7 +248,7 @@ namespace AdHoc {
{
Lock(lock);
removeFrom(r, inUse);
- poolSize.release();
+ release();
}
template<typename R>
diff --git a/libadhocutil/unittests/testResourcePool.cpp b/libadhocutil/unittests/testResourcePool.cpp
index a5f06a2..cecfb46 100644
--- a/libadhocutil/unittests/testResourcePool.cpp
+++ b/libadhocutil/unittests/testResourcePool.cpp
@@ -7,7 +7,7 @@
#ifdef __cpp_lib_semaphore
# include <semaphore>
#else
-# include "polyfill-semaphore.h"
+# include "polyfill-semaphore.h" // IWYU pragma: keep
#endif
#include <atomic>
#include <list>
@@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(threading1, *boost::unit_test::timeout(10))
}
static void
-acquireAndKeepFor1Second(TRPSmall * pool, AdHoc::SemaphoreType & s)
+acquireAndKeepFor1Second(TRPSmall * pool, AdHoc::ResourcePoolBase::SemaphoreType & s)
{
auto r = pool->get();
static std::mutex m;
@@ -348,7 +348,7 @@ acquireAndKeepFor1Second(TRPSmall * pool, AdHoc::SemaphoreType & s)
BOOST_AUTO_TEST_CASE(threading2)
{
TRPSmall pool;
- AdHoc::SemaphoreType s {0};
+ AdHoc::ResourcePoolBase::SemaphoreType s {0};
std::thread t1([&pool, &s]() {
acquireAndKeepFor1Second(&pool, s);
});
@@ -420,32 +420,14 @@ BOOST_AUTO_TEST_CASE(createFail)
BOOST_REQUIRE_EQUAL(0, MockResource::count);
BOOST_REQUIRE_EQUAL(0, pool.availableCount());
BOOST_REQUIRE_EQUAL(0, pool.inUseCount());
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
BOOST_REQUIRE_THROW(pool.get(), std::exception);
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
BOOST_REQUIRE_THROW(pool.get(0), std::exception);
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
BOOST_REQUIRE_THROW(pool.get(100), std::exception);
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
BOOST_REQUIRE_EQUAL(0, MockResource::count);
BOOST_REQUIRE_EQUAL(0, pool.availableCount());
BOOST_REQUIRE_EQUAL(0, pool.inUseCount());
BOOST_REQUIRE_THROW(pool.get(), std::exception);
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
BOOST_REQUIRE_THROW(pool.get(), std::exception);
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
}
BOOST_AUTO_TEST_CASE(returnFail)
@@ -456,15 +438,9 @@ BOOST_AUTO_TEST_CASE(returnFail)
BOOST_CHECK(rh);
BOOST_REQUIRE_EQUAL(0, pool.availableCount());
BOOST_REQUIRE_EQUAL(1, pool.inUseCount());
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(2, pool.freeCount());
-#endif
}
BOOST_REQUIRE_EQUAL(0, pool.availableCount());
BOOST_REQUIRE_EQUAL(0, pool.inUseCount());
-#ifndef __cpp_lib_semaphore
- BOOST_REQUIRE_EQUAL(3, pool.freeCount());
-#endif
}
BOOST_AUTO_TEST_CASE(exception_msgs)