Header only library purposed to create pool of some resources like keep-alive connections. Supports sync and async interfaces. Based on boost.
- CMake >= 3.12
- GCC or Clang C++ compilers with C++17 support.
- Boost >= 1.66
Project uses CMake. Build need only to run tests, examples and benchmarks:
mkdir build
cd build
cmake ..
make -j $(nproc)
ctest -V
examples/sync_pool
examples/async_pool
benchmarks/resource_pool_benchmark_async
Include as subdirectory into your CMake project or copy folder include.
The handle contains iterator to boost::optional
of resource value in pool.
Declared as type handle.
Constructs with one of strategies that uses in destructor:
- waste -- resets iterator if handle is usable.
- recycle -- returns iterator to pool if handle is usable.
Pool contains slots for resources that means handle iterator may refers to empty boost::optional
.
Client always must check value before using by method:
bool empty() const;
Access to value provides by methods:
value_type& get();
const value_type& get() const;
value_type *operator ->();
const value_type *operator ->() const;
value_type &operator *();
const value_type &operator *() const;
value_type
-- resource type.
Value of handle changes by method:
void reset(value_type&& res);
To drop resource use method:
void waste();
To return resource into pool use method:
void recycle();
Both methods makes handle unusable that could be checked by method:
bool unusable() const;
Calling one of these methods for unusable handle throws an exception error::unusable_handle
.
Based on std::condition_variable
.
Use type sync::pool. Parametrize resource type:
template <class Value
class Impl = detail::pool_impl<Value, std::condition_variable> >
class pool;
Pool holds boost::optional
of resource type.
Example:
using fstream_pool = pool<std::fstream>;
Object construction requires pool capacity:
pool(
std::size_t capacity,
time_traits::duration idle_timeout = time_traits::duration::max(),
time_traits::duration lifespan = time_traits::duration::max()
);
idle_timeout
defines maximum time interval to keep unused resource in the pool. Check for elapsed time happens on resource allocation.lifespan
defines maximum time interval to keep resource. Check for elapsed time happens on resource allocation and recycle.
Example:
fstream_pool pool(42);
Use one of these methods:
std::pair<boost::system::error_code, handle> get_auto_waste(
time_traits::duration wait_duration = time_traits::duration(0)
);
returns resource handle when it will be available with auto waste strategy.
std::pair<boost::system::error_code, handle> get_auto_recycle(
time_traits::duration wait_duration = time_traits::duration(0)
);
returns resource handle when it will be available with auto recycle strategy.
Recommends to use get_auto_waste
and explicit call recycle
.
Example:
auto r = pool.get(time_traits::duration(1));
const auto& ec = r.first;
if (ec) {
std::cerr << "Can't get resource: " << ec.message() << std::endl;
return;
}
auto& h = r.second;
if (h.empty()) {
h.reset(create_resource());
}
use_resource(h.get());
Following method allows to force all available and used handles to be wasted:
void invalidate();
All currently available but not used handles will be wasted. All currently used handles will be wasted on return to the pool.
Based on boost::asio::io_context
. Uses async queue with deadline timer to store waiting resources requests.
Use type async::pool. Parametrize resource type:
template <class Value,
class IoContext = boost::asio::io_context,
class Impl = default_pool_impl<Value, IoContext>::type>
class pool;
Pool holds boost::optional
of resource type.
Example:
using fstream_pool = pool<std::fstream>;
Object construction requires reference to io service, capacity of pool, queue capacity:
pool(
io_context_t& io_context,
std::size_t capacity,
std::size_t queue_capacity,
time_traits::duration idle_timeout = time_traits::duration::max(),
time_traits::duration lifespan = time_traits::duration::max()
);
idle_timeout
defines maximum time interval to keep unused resource in the pool. Check for elapsed time happens on resource allocation.lifespan
defines maximum time interval to keep resource. Check for elapsed time happens on resource allocation and recycle.
Example:
boost::asio::io_context io;
fstream_pool pool(io, 13, 42);
Use one of these methods:
template <class CompletionToken>
void get_auto_waste(
boost::asio::io_context& io,
CompletionToken&& token,
const time_traits::duration& wait_duration = time_traits::duration(0)
);
returns resource handle when it will be available with auto waste strategy.
template <class CompletionToken>
void get_auto_recycle(
boost::asio::io_context& io,
CompletionToken&& token,
const time_traits::duration& wait_duration = time_traits::duration(0)
);
returns resource handle when it will be available with auto recycle strategy.
Type CompetionToken
must provide interface:
void operator ()(
const boost::system::error_code&,
handle
);
or it can be any valid completion token from Boost.Asio like boost::asio::yield_context
, boost::asio::use_future
and so on.
Recommends to use get_auto_waste
and explicit call recycle
.
If error occurs ec
will be not ok and handle
will be unusable.
Example with classic callbacks:
struct on_create_resource {
handle h;
on_create_resource(handle h) : h(std::move(h)) {}
void operator ()(const boost::system::error_code& ec, handle::value_type&& r) {
if (ec) {
std::cerr << "Can't create resource: " << ec.message() << std::endl;
return;
}
h.reset(std::move(r));
use_resource(h.get());
}
};
struct handle_get {
void operator ()(const boost::system::error_code& ec, handle h) {
if (ec) {
std::cerr << "Can't get resource: " << ec.message() << std::endl;
return;
}
if (h.empty()) {
async_create_resource(on_create_resource(std::move(h)));
} else {
use_resource(h.get());
}
}
};
pool.get(handle_get(), time_traits::duration(1));
Example with Boost.Coroutines:
boost::asio::spawn(io, [&](boost::asio::yield_context yield) {
auto h = pool.get(yield, time_traits::duration(1));
if (h.empty()) {
h.reset(create_resource(yield));
}
use_resource(h.get());
}
Following method allows to force all available and used handles to be wasted:
void invalidate();
All currently available but not used handles will be wasted. All currently used handles will be wasted on return to the pool.
Source code can be found in examples directory.