diff options
-rw-r--r-- | libadhocutil/polyfill-semaphore.h | 1 | ||||
-rw-r--r-- | libadhocutil/resourcePool.cpp | 30 | ||||
-rw-r--r-- | libadhocutil/resourcePool.h | 55 | ||||
-rw-r--r-- | libadhocutil/resourcePool.impl.h | 31 | ||||
-rw-r--r-- | libadhocutil/unittests/testResourcePool.cpp | 30 |
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) |