Overview
This guide covers practical usage patterns for the ARRP resource pool library.
Basic Usage
Creating a Pool
#include "siddiqsoft/resource_pool.hpp"
siddiqsoft::arrp::resource_pool<std::string>::auto_add_policy::AutoGrow
);
Thread-safe auto-returning resource pool for modern C++.
Populating the Pool
pool.checkin(std::make_shared<DatabaseConnection>());
for (int i = 0; i < 10; ++i) {
pool.checkin(std::make_shared<DatabaseConnection>());
}
Borrowing Resources
try {
auto resource = pool.checkout();
resource->query("SELECT * FROM users");
} catch (const std::runtime_error& e) {
std::cerr << "Failed to borrow resource: " << e.what() << std::endl;
}
Advanced Patterns
Custom Factory Callback
auto conn = DatabaseConnection::create();
std::move(conn),
[&p](DatabaseConnection&& res) {
p.checkin(std::move(res));
}
);
}
);
for (int i = 0; i < 100; ++i) {
auto conn = pool.checkout();
conn->query("SELECT * FROM users");
}
RAII wrapper for managing resource lifecycle with automatic return to pool.
Multi-threaded Usage
#include <thread>
#include <vector>
for (int i = 0; i < 10; ++i) {
pool.checkin(std::make_shared<DatabaseConnection>());
}
std::vector<std::jthread> threads;
for (int t = 0; t < 4; ++t) {
threads.emplace_back([&pool]() {
for (int i = 0; i < 100; ++i) {
try {
auto conn = pool.checkout();
conn->query("SELECT * FROM users");
} catch (const std::runtime_error&) {
}
}
});
}
Monitoring Pool State
auto state = pool.to_json();
std::cout << "Capacity: " << state["capacity"] << std::endl;
std::cout << "Available: " << state["size"] << std::endl;
std::cout << "Checked out: " << state["checkedout"] << std::endl;
std::cout << "Total load: " << state["load"] << std::endl;
auto counters = state["counters"];
std::cout << "Total borrows: " << counters["borrow"] << std::endl;
std::cout << "Total returns: " << counters["return"] << std::endl;
std::cout << "Auto-created: " << counters["newitems"] << std::endl;
Error Handling
Handling Pool Exhaustion
auto borrow_with_retry = [&pool](int max_retries = 3) {
for (int attempt = 0; attempt < max_retries; ++attempt) {
try {
return pool.checkout();
} catch (const std::runtime_error&) {
if (attempt < max_retries - 1) {
std::this_thread::sleep_for(std::chrono::milliseconds(10 * (attempt + 1)));
} else {
throw;
}
}
}
};
siddiqsoft::arrp::resource_pool<Resource>::auto_add_policy::AutoGrow
);
Exception Safety
try {
auto resource = pool.checkout();
throw std::runtime_error("Something went wrong");
} catch (const std::exception&) {
}
EXPECT_EQ(1u, pool.size());
Resource Types
Using shared_ptr
pool.checkin(std::make_shared<DatabaseConnection>());
{
auto conn = pool.checkout();
conn->query("SELECT * FROM users");
}
Using unique_ptr
pool.checkin(std::make_unique<DatabaseConnection>());
{
auto conn = pool.checkout();
conn->query("SELECT * FROM users");
}
Using Custom Types
class MyResource {
public:
void doWork() { }
};
pool.checkin(MyResource());
{
auto res = pool.checkout();
res->doWork();
}
Resource Invalidation
Invalidating Moved Resources
{
auto resource = pool.checkout();
auto extracted = std::move(*resource);
resource.invalidate();
extracted.doWork();
}
Invalidating Consumed Resources
{
auto resource = pool.checkout();
process_and_consume(*resource);
resource.invalidate();
}
Troubleshooting
Avoiding Deadlocks
Problem: Application hangs when calling pool methods.
Cause: Factory callback calls pool methods.
Solution:
auto pool = resource_pool<Resource>(
[](auto& p) -> scoped_resource<Resource> {
auto res = p.checkout();
return scoped_resource<Resource>(res, ...);
}
);
auto pool = resource_pool<Resource>(
[](auto& p) -> scoped_resource<Resource> {
return scoped_resource<Resource>(
Resource::create(),
[&p](Resource&& res) { p.checkin(std::move(res)); }
);
}
);
Pool is Empty
Problem: Getting "No items in the pool" exception.
Solutions:
- Pre-populate pool before use
- Use AutoGrow policy
- Implement retry logic with backoff
Performance Issues
Problem: Pool operations are slow.
Solutions:
- Increase pool size to reduce contention
- Ensure factory callbacks are fast
- Monitor with to_json() to check utilization
- Use appropriate resource types (shared_ptr vs unique_ptr)
Best Practices
- Always use RAII: Let scoped_resource handle resource return
- Pre-populate pools: Add resources before concurrent access
- Handle exceptions: Catch std::runtime_error from checkout()
- Keep factories simple: Factory callbacks should only create resources
- Monitor utilization: Use to_json() to track pool health
- Use appropriate types: Prefer shared_ptr or unique_ptr
- Test concurrency: Verify thread safety with your specific use case
- Avoid manual checkin(): Only use in advanced scenarios
- Document assumptions: Clearly document resource lifecycle expectations
- Profile under load: Test with realistic concurrent access patterns